ES6入门笔记------19-26

1.Class的基本语法

<1>定义相关:

    1.可以在看作是语法糖:类的数据类型就是函数,类本身就指向构造函数,使用的时候,同构造函数,使用new命令。

    2.类的方法,除了constructor(这个=原型的constructor,指向其本身),其他都定义在prototype对象上,所以新方法可以通过Object.assigh(对象原型,方法)。

    3.类的内部定义的所有方法都是不可枚举,如果采用ES5构造函数的写法,就变成可以枚举的了。

<2>类和模块内部默认使用严格模式

<3>constructor方法:类的默认方法,通过new命令生成对象实例的时候自动调用,每个类必须要有,如果没有显示定义,一个空的constructor方法会被默认添加。

<4>类的实例对象:类必须要new调用,实例的属性除非显示定义在其本身,即this对象上,否则都是定义在原型上。

                                所有实例共享一个原型对象,所以可以通过实力的__proto__属性为类添加方法

<5>Class表达式:const Myclass=class Me{},这里的类的名字是Myclass,Me只能在Class内部代码可用,指代当前类。如果内部没用到,可以省略。采用表达式,可以写立即执行的Class,eg:let person=new class{}(参数)

<6>类不存在变量提升

<7>私有方法:ES6本身不提供,可以在方法前加下划线代表这是和内部使用的私有方法,但其实外部依旧可以使用。

可以将私有方法移除,内部调用该方法call。或者利用Symbol的唯一性将私有方法的名字命名为一个Symbol值.

有一个提案,在私有属性前面加#代表,私有和公有可以同名

<8>this:Class内的this默认指向类的实例,但是如果将Class内的方法单独取出来使用,this将会指向运行时 所在的环境。要想绑定this,可以bind,箭头函数,Proxy

<9>Class的getter和setter函数:get/set 属性名(){},该函数能拦截该属性的存取行为

<10>静态方法:类中定义的方法都会被实例继承,但是如果在一个方法前加static,表示该方法不会被实例继承,而是直接通过类调用,称为静态方法。

相关:

    1.父类的静态方法可被子类继承

    2.静态属性指的是Class本身的属性,只可以是Class.propname来定义更改,不可以是在Class内同方法一样定义。因为ES6明确定义Class内只有静态方法,没有静态属性。

<11>实例属性:Class的实例属性可以用等式写入类的定义中,以前是写在constructor里面。如果该属性在constructor里已定义,允许在Class内直接列出(没有任何赋值定义的操作);

新写法中可以在实例属性前面加static就可以是静态属性

<12>new.target:通过new调用的Class,在Class内部调用new.target会返回当前Class,子类继承父类时new.target返回子类

 

2.Class的继承

<1>概念:通过extends实现继承,子类中的super代表父类的构造函数(可以看作父类的this),因为子类没有自己的this对象,而是继承父类的,如果不调用super方法,就得不到父类的this对象。

<2>Object.getPrototyoeOf(子类)可以获取他的父类

<3>super关键字:

    1.作为函数使用:代表父类的构造函数,ES6要求,子类的构造函数必须执行一次super函数。但是super被的this指的是子类。只能用在子类的构造函数中。

    2.作为对象使用:在普通方法中使用指向父类的原型对象(定义在父类实例上的方法或者实例是无法通过super调用),在静态方法中指向父类。通过super调用父类的方法时,super绑定子类的this

<4>类的 prototype 属性和__proto__属性

1.子类的__proto__属性表示构造函数的继承,总是指向父类。

2.子类 prototype 属性的__proto__属性表示方法的继承,总是指向父类的
prototype 属性

<5>extends的继承目标:extends关键字后面可以跟很多种类型的值,如果是class继承的话,父类可以是任意函数

<6>ES6可以定义子类继承原生的构造函数。

 

3.修饰器

<1>类的修饰:修饰器对类的行为改变发生在编译时

@修饰器名字(参数)------默认为目标类,如果在修饰器外封装有函数,可以按需传参

class 类的名字

<2>方法的修饰:修饰类里的方法,写法同上,可传参为三个,目标类,修饰的属性名(方法名),该属性的描述对象

     如果一个方法有多个修饰器,那么会优先按序执行所有修饰器的外层,然后再反序执行所有的内层

<3>修饰器只能用于修饰了类和类的方法,不能用于函数,因为函数会提升,而类不会

<4>core-decorators.js:第三方模块,提供了几种常见修饰器

    1.@autobind:使得方法中的 this 对象绑定原始对象

    2.@readonly:使得属性和方法不可写

    3.@override:检查子类的方法是否正确覆盖了父类的同名方法,如果不正确(子类方法写的不对或者找不到父类相应的方法)会报错。

    4.@deprecate(别名@deprcated):在控制台显示一条警告,表示该方法将废除。

    5.@suppressWarnings:器抑制 decorated 修饰器导致的 console. warn()调用,但
异步代码发出的调用除外

<5>使用修饰器实现自动发布:发布订阅库:Postal.js

<6>修饰器可以实现Mixin模式,用Object.assign(类.prototype,一系列方法)。

      不过这样会改写prototype对象

<7>Trait:一种修饰器,类似Minxin,但是提供了更多功能,比如同名方法的冲突等等,以第三方模块traits-decorator为例

@traits(参数为要混入的类或者对象),如果混入的具有同名方法,会报错,需要:

1.可能存在同名方法,将其排除掉写为:类名::excludes(同名方法的名字)

2.将其改名写为:类名::alias(同名方法的名字:新名字)

 

3.Module的语法

<1>export:输出函数、变量、类,写法:

        (1)export var 变量名=xxx;      多个就写多个export

        (2)expory {变量名}     多个{}里逗号隔开

此外可以用as重命名(对外的接口),接口取到模块内实时的值,而CommonJS模块输出的是值的缓存

export只要处在模块顶层就可以,位于块级作用域内会报错,import也是。

<2>import:加载,写法:import {变量或类或对象} from '地址或模块名(如果直接模块名,则配置文件内要说明位置)'

      import必须接受一个对象({}),在里面指定导入的变量名,如果要重命名,也是用as

      import具有提升效果,会提升到整个模块的头部并首先执行。

<3>模块的整体加载:import * as xx from ww 可以用*表示整体加载,即所有的输出值都在*,这里as成xx

<4>export default命令:export default fn,这样用户在import的时候就可以为export的东西指定任意名字,但import的时候后面只能跟名字,不能再跟{}。一个模块只能有一个默认输出(只能对应一个方法)

<5>export和import的复合写法

<6>模块继承

<7>跨模块常量:这些常量写在一个专门的constants目录里,然后合并再index.js里

<8>import():提案:参数为要加在模块的位置,实现动态加载,类似Node的require,但是是异步加载

 

4.Module的加载实现

<1>传统方法:异步加载脚本script标签加defer或async。前者要等整个页面加载完才会执行,后者一旦下载完渲染引擎会中断,执行完这个脚本再渲染。多个的话,defer按序,async无序

<2>加载规则:浏览器加载ES6模块也用script标签,type=“module”,其功能等同defer

外部需要注意:

1.代码在模块作用域之中运行,不是在全局,模块内的顶层变量是外部不可见的

2.模块脚本采用严格模式

3.模块中可以使用import和export

4.模块中顶层的this返回undefined,而不是指向window,即是在顶层使用this无意义

5.同一个模块如果加载多次,只执行一次

<3>ES6模块与CommonJS模块的差异

    1.CommonJS模块输出的是一个值的复制,ES6模块输出的是值的引用

    2.CommonJS模块是运行时加载,ES6模块是编译时输出接口

1的详解:CommonJS一旦输出一个值,模块内的变化将无法影响到该值(eg:模块内的改写该值函数输出,执行后也不会改写该值),要想能改写,除非把该值写成一个函数

<4>Node加载

    概述:node有自己的CommonJS模块格式,与ES6不兼容,处理ES6比较麻烦,所以现在还是分开用各自的加载方案。在静态分析阶段只要有import或export语句,node就认为是ES6,否则是CommonJS

    1.import加载CommonJS模块:Node的CommonJS模块输出都定义在module.exports属性上,所以Node环境中,用import加载CommonJS模块,Node会自动将module.exports属性当作export default。如果采用整体输入的写法(import * as xxx),那么用xxx.default来获取module.exports

    2.require加载ES6模块:所有输出的接口会变成输入对象的属性,而且由于缓存机制,export后的重新赋值不会在模块外反映出来。

<5>循环加载

<6>ES6转码:ES6 module transpiler 和 SystemJS
 

5.编程风格

<1>let完全替代var且没有副作用,能用const尽量用,尤其在全局环境

<2>静态字符串一律用单引号或反引号,不用双引号。动态用反引号(const b = `foo${a}bar`   //a为变量)

<3>使用数组成员对变量赋值时,优先使用解构赋值const [first , second]= arr;

      函数参数如果是对象的成员时,优先使用解构赋值

      函数如果返回多个值,优先用对象的解构赋值而不是数组,便于以后添加以及更改顺序

<4>对象:单行定义的对象,最后一个不以逗号结尾,多行的以逗号结尾;

            对象尽量静态化,一旦定义不要随便添加新属性,如果实在要加,要使用Object.assign

            动态属性名,在创建对象的时候使用属性表达式定义。

<5>数组:使用...数组,来复制数组,使用Array.from方法将类似数组的对象转为数组。

<6>函数:立即执行的函数可以写成箭头函数的形式,尽量用箭头函数

            简单的、单行的、不会复用的函数用箭头;行数较多,比较复杂的还是用传统

            所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数。

            eg:function divide(a , b , { option= false} = {}) { }

            函数体内不用argument变量,用...代替,前者是类数组对象,后者是真正的数组

<7>Map结构:注意区分Object和Map,只有模拟实体对象时才使用 Object

<8>Class:用Class取代prototype操作,使用extends实现继承

<9>模块:使用import取代require,使用export取代module.exports(不要同时使用export和export default)

            如果模块默认输出一个函数,函数名首字母应该小写,如果默认输出一个对象,对象首字母应该大写

<10>ESLint使用:语法规则和代码风格检查工具

 

6.读懂ECMAScript规格

需要再回顾

 

7.ArrayBuffer

<1>二进制数组:和操作系统的原生接口进行二进制通信,该数组由ArrayBuffer对象(代表储存二进制数据的一段内存

),TypedArray 视图(读写简单类型的二进制数据),DataView 视图(读写类型的二进制数据)

<2>ArrayBuffer对象:也是一个构造函数,可分配一段可以存放数据的连续内存区域

         var buf=new ArrayBuffer(32);   //生成一段32字节的内存区域,字节默认都是0

         var dataView=new DataView(buf);   //创建DataView视图,需提供ArrayBuffer对象实例作为参数

         dataView.getUint8(0)//以不带符号的8位整数格式读取第一个元素

         // TypedArray视图不是一个构造函数,而是一组,所以它的用法,如下,此外它还可以接受普通数组作为参数

         var xl =new Int32Array (buf);     //此例是创建32位带符号整数,如果有创建多个视图,一个视图修改底层内存会影响另一个
         xl[0] = 1 ;

<3>ArrayBuffer的函数:

         ArrayBuffer.prototype.byteLength   //返回所分配内存区域的字节长度

         ArrayBuffer.prototype.slice()     //允许内存区域的一部分复制生成一个新的ArrayBuffer对象,参数1,2代表开始(含开始)和结束(不含结束)的位置,无第2参数则到对象结尾

         ArrayBuffer.isView     //返回Boolean,表示参数是否为ArrayBuffer的视图实例

<4>TypedArray视图:9种,都是构造函数(参数1为ArrayBuffer对象,2为开始处,3为结束处),像普通数组,区别:成员都是同一类型,成员连续不会有空位,成员默认值为0。

        TypedArray的构造函数可以不通过ArrayBuffer,而是直接分配内存生成

        TypedArray的构造函数可以接受另一个的TypedArray的实例作为参数。新数组只是复制了参数数组的值,对应的底层内存不一样,新数组会开辟一段新内存储存数据。

<5>数组方法:普通数组的操作方法合属性对TypedArray数组完全适用,但没有concat方法

<6>字节序:需要结合实际再了解,另外BYTES_PER_ELEMENT属性表示数据类型占据的字节数

<7>ArrayBuffer与字符串的互相转换:前提是字符串的编码方法是确定的。

<8>不同的视图类型能容纳的数值范围是确定的,如果超出,就会出现溢出,TypedArray的处理就是抛出溢出的位,其他的有不同

<9>TypedArray.prototype的属性和方法:

        buffer:返回整段内存区域对应的ArrayBuffer对象

        bytelength:占据的内存长度,单位为字节

        byteOffset:返回TypedArray数组从ArrayBuffer对象的哪个字节开始

        length:有多少个成员

        set():复制数组(内存的复制),参数1为复制的目标,2为从哪一个成员开始复制

        subarray():对TypedArray数组的一部分再建立一个新的视图,参数1为开始处,2为结束处

        slice():返回一个指定位置的新的TypedArray实例,参数代表位置,可为负数,即逆向计数

<10>TypedArray数组的所有构造函数都有of和from方法,前者将参数转为一个TypedArray实例,后者接受一个可遍历的数据结构作为参数,返回一个基于此结构的TypedArray实例,接受函数作为第二个参数,功能类似map。

<11>dataView视图:用域处理网络设备传来的数据,可以自行设定大端字节或小端字节,存取各有8个方法。取的参数代表读取位置,存的参数代表存的位置,数据,大小端设定(true为小段,false和undefined为大端)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值