《ES6标准入门》学习总结

第1章 ECMAScript 6简介

1.ES是JS的规格,JS是ES的实现。

2.es-checker模块可以查看本机对ES6的支持程度。

3.Babel是转码器,配置文件是.babelrc,可以通过babel-cli进行命令行转码。

4.babel-node是随着babel-cli一起安装的,babe-node命令可以直接运行ES6脚本。

5.babel-register只会对require命令加载的文件进行转码,使用babel-core可以调用Babel的API进行转码。

6.babel-polyfill为当前环境提供一个垫片,可以转码JS的新的API。

7.Babel也可以用于浏览器环境。可以使用babel-standalone模块提供的浏览器版本,将其插入网页。

8.ESLint和测试框架Mocha需要Babel进行前置转码。

9.Traceur转码器可以直接插入网页,可以进行在线转换或命令行转换,也可以用于Node环境转换。

 

第2章 let和const命令

1.for循环设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

2.var命令会发生变量提升,即变量可以在声明前使用,值为undefined。为了纠正这种现象,let命令改变了语法行为。它所声明的变量一定要在声明后使用,否则便会报错。

3.如果区块中存在let和const命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。只要声明之前就使用这些变量,就会报错。这在语法上成为暂时性死区(TDZ)。

4.let不允许在相同作用域内重复声明同一个变量。

5.ES5只有全局作用域和函数作用域,ES6新增了块级作用域。

6.在ES5中,函数声明会被提升到函数头部。应该避免在块级作用域内声明函数。如果确实需要,应该写成函数表达式的形式。

7.块级作用域可以变为表达式,即可以返回值,办法就是在块级作用域之前加上do,使它变为do表达式。

8.const实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。

9.ES6声明变量的6种方法:var、function、let、const、import和class。

10.在浏览器和Web Worker中,self也指向顶层对象。

 

第3章 变量的解构赋值

1.如果解构不成功,变量的值就等于undefined。

2.不完全解构,即等号左边的模式只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

3.对于Set结构,也可以使用数组的解构赋值。只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值。

4.解构赋值允许指定默认值。默认值生效的条件是,对象的属性值严格等于undefined。

5.字符串、数值、布尔值、函数参数也可以解构赋值。

6.不要在模式中放置圆括号,赋值语句的非模式部分可以使用圆括号。

7.变量解构赋值的用途有:交换变量的值、从函数返回多个值、函数参数的定义、提取JSON数据、函数参数的默认值、遍历Map结构、输入模块的指定方法。

 

第4章 字符串的扩展

1.ES6加强了对Unicode的支持,并且扩展了字符串对象。

2.由于charAt()和charCodeAt()的局限性,ES6新增了codePointAt()方法。

3.使用for...of循环会正确识别32位的UTF-16字符。

4.String.fromCharCode()不能识别大于0xFFFF的码点,String.fromCodePoint()可以识别大于0xFFFF的码点。

5.ES6为字符串添加了遍历器接口,使得字符串可以由for...of循环遍历。

6.at方法可以识别Unicode编号大于0xFFFF的字符,返回正确的字符。

7.ES6为字符串提供了normalize方法,用来将字符的不同表示方法统一为同样的形式,这称为Unicode正规化。

8.ES6新增了includes()、startsWith()、endsWith()、repeat()、padStart()、padEnd()方法。

9.ES6新增了模板字符串,可以嵌套使用。

10.eval()方法可以将字符串变为函数。

11.模板字符串可以紧跟在一个函数的后面,该函数将被调用来处理这个模板字符串。这被称为标签模板的功能。标签模板的一个重要的应用就是过滤HTML字符串,防止用户输入恶意内容,也可用于多语言切换。

12.模板处理函数的第一个参数(模板字符串数组)还有一个raw属性,保存的是转义后的原字符串。

13.ES6还为原生的String对象提供了一个raw方法。

 

第5章 正则的扩展

1.new RegExp时,第一个参数是字符串或正则表达式,第二个参数是修饰符。

2.字符串具有match、replace、search、split4个方法可以使用正则表达式。

3.ES6对正则表达式增加了u修饰符,含义为Unicode模式,用来正确处理大于\uFFFF的Unicode字符。

4.y修饰符叫做粘连修饰符,s修饰符是dotAll模式。

5.现在js可支持先行断言、先行否定断言、后行断言、后行否定断言。

6.提案引入\p和\P,允许正则表达式匹配符合Unicode某种属性的所有字符。

7.正则表达式使用圆括号进行组匹配,具名组匹配允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。

8.如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法。

 

第6章 数值的扩展

1.ES6提供了二进制和八进制的新写法,分别用0b和0o表示。

2.ES6在Number对象上提供了Number.isFinite()、Number.isNaN()、Number.parseInt()、Number.parseFloat()、Number.isInteger()方法。

3.Number.EPSILON是一个极小的常量,是一个可以接受的误差范围。

4.Number有最大安全整数和最小安全整数的概念,用Number.isSafeInteger()来判断。

5.Math对象新增的方法有Math.trunc()、Math.sign()、Math.cbrt()、Math.clz32()、Math.imul()、Math.fround()、Math.hypot()。

6.ES6新增了4个对数相关的方法:expm1()、log1p()、log10()、log2(),新增了6个双曲函数方法。

7.Math.signbit()方法判断一个数的符号位是否已经设置。

8.ES6新增了指数运算符**。

9.新的数据类型Integer只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。Integer类型的数据必须使用后缀n来表示。

 

第7章 函数的扩展

1.函数参数新增了默认值用法,可与解构赋值默认值结合使用,定义了默认值的参数应该是函数的尾参数。

2.如果非尾部的参数设置默认值,实际上这个参数是无法省略的。

3.指定了默认值以后,函数的length属性将返回没有指定默认值的个数。

4.利用参数默认值可以指定某一个参数不得省略,如果省略就抛出一个错误。

5.ES6引入了rest参数,用于获取函数的多余参数,这样就不需要使用arguments对象了。

6.只要函数参数使用了默认值、解构赋值或扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。

7.函数的name属性返回该函数的函数名。

8.箭头函数函数体内this对象就是所定义时所在的对象,而不是使用时所在的对象。

9.this指向的固定化并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以不能用作构造函数。

10.箭头函数可以嵌套,可以绑定this对象,大大减少了显式绑定this对象的写法(call、apply、bind)。

11.函数绑定运算符即双冒号(::)用来取代call、apply、bind调用。

12.尾调用就是指某个函数的最后一步是调用另一个函数,尾调用优化即只保留内层函数的调用帧,大大节省内存。

13.尾调用自身就成为尾递归。尾递归的实现往往需要改写递归函数,确保最后一步只调用自身。

14.柯里化(currying)是将多参数的函数转换成单参数的形式。

15.ES6的尾调用优化只在严格模式下开启,正常模式下是无效的。

16.提案允许函数的最后一个参数有尾逗号。

 

第8章 数组的扩展

1.扩展运算符可以替代数组的apply方法。

2.扩展运算符可用于合并数组、与解构赋值结合、函数的返回值、字符串、实现了Iterator接口的对象(如NodeList对象、arguments对象)、Map、Set、Generator函数。

3.Array.from()方法用于将类数组对象和可遍历对象转为真正的数组。

4.扩展运算符背后调用的是遍历器接口Symbol.iterator。

5.任何有length属性的对象,都可以通过Array.from方法转为数组,而这种情况扩展运算符无法转换。

6.Array.from()可以接受第二个参数,作用类似于数组的map方法。

7.Array.of()方法用于将一组值转换为数组。

8.数组实例的copyWithin方法会在当前数组内部将指定位置的成员复制到其他位置,会修改当前数组,参数为target,start=0,end=this.length。

9.数组实例的find()和findIndex()用于找出第一个符合条件的数组成员。

10.entries()、keys()、values()用于遍历数组。

11.数组实例的includes()可以替代indexOf()方法。

12.数组的空位指数组的某一个位置没有任何值。由于空位的处理规则非常不统一,所以建议避免出现空位。

 

第9章 对象的扩展

1.ES6允许直接写入变量和函数作为对象的属性和方法,新增了属性名表达式。

2.对象的方法也有name属性。

3.ES6新增了判断相等的Object.is()。

4.Object.assign()方法是浅复制,可用于为对象添加属性、为对象添加方法、克隆对象、合并多个对象、为属性指定默认值。

5.ES6共有5种方法可以遍历对象的属性:for...in、Object.keys(obj)、Object.getOwnPropertyNames(obj)、Object.getOwnPropertySymbols(obj)、Reflect.ownKeys(obj)。

6.对象具有__proto__属性,指向对象的原型。可以通过Object.setPrototypeOf()设置原型,通过Object.getPrototypeOf()获得原型。

7.Object也具有keys()、values()、entries()方法。

8.对象也可以使用扩展运算符。

9.Object.getOwnPropertyDescriptors()可以返回指定对象自身属性的描述对象。

10.Null传导运算符?.可以简化对象的判断。

 

第10章 Symbol

1.为了保证属性名不会发生冲突,ES6引入了独一无二的Symbol类型。

2.Symbol是JS的第7种数据类型,前6种分别是Undefined、Null、Boolean、Number、String、Object。

3.Sumbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时比较容易区分。

4.Symbol可用作对象的属性名,还可以用于定义一组常量。

5.魔术字符串指的是在代码中多次出现,与代码形成强耦合的某一个具体的字符串或数字。风格良好的代码,应该尽量消除魔术字符串,而由含义清晰的变量代替。

6.用Object.getOwnPropertySymbols()可以获取指定对象的所有Symbol属性名。Reflect.ownKeys()可以返回所有类型的键名。

7.以Symbol值作为名称的属性不会被常规方法遍历得到。我们可以利用这个特性为对象定义一些非私有但又希望只用于内部的方法。

8.Symbol.for()会被登记在全局环境中供搜索,而Symbol()不会。Symbol.keyFor()返回一个已登记的Symbol类型值的key。

9.把Symbol.for()用于global属性,可以实现Singleton模式,保证不会被无意间覆盖,但还是可以被改写。

10.除了定义自己使用的Symbol值,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。

11.ES6内置的Symbol值有hasInstance、isConcatSpreadable、species、match、replace、search、split、iterator、toPrimitive、toStringTag、unscopables。

 

第11章 Set和Map数据结构

1.Set可以用于数组去重,通过size可以返回成员总数,具有add()、delete()、has()、clear()4个操作方法。

2.Set结构的实例有keys()、values()、entries()、forEach()4个遍历方法。

3.数组的map和filter方法结合扩展运算符也可以用于Set,使用Set可以容易地实现并集(Union)、交集(Intersect)和差集(Difference)。

4.WeakSet结构与Set相似,区别在于,它的成员只能是对象,WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用。

5.WeakSet不可遍历,具有add()、delete()、has()三个方法。

6.WeakSet的一个用处是储存DOM节点,而不用担心这些节点从文档移除时会引发内存泄漏。

7.由于对象只能用字符串作为键,为了解决这个问题,ES6提供了Map数据结构,各种类型的值(包括对象)都可以当键。

8.Map具有set()、get()、delete()、has()、clear()方法,通过size可以获得大小。

9.Set和Map都可以用来生成新的Map,Map结构的实例有keys()、values()、entries()、forEach()4个遍历方法。forEach方法还可以接受第二个参数,用于绑定this。

10.Map可以与数组相互转换,与对象相互转换,与JSON相互转换。

11.Map的键名如果都是字符串,可以选择转为对象JSON,若Map的键名有非字符串,可以选择转为数组JSON。

12.WeakMap只接受对象作为键名,键名所指向的对象不计入垃圾回收机制,避免产生内存泄漏。

13.WeakMap没法遍历,也无法清空,其应用场景就是以DOM节点为键名的场景,另一个用处是部署私有属性。

 

第12章 Proxy

1.Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”,即对编程语言进行编程。

2.ES6原生提供Proxy构造函数,用于生成Proxy实例,写法为var proxy = new Proxy(target,handler)。第一个参数是所要代理的目标对象,第二个参数是一个配置对象。

3.Proxy实例的方法:get()、set()、apply()、has()、construct()、deleteProperty()、defineProperty()、getOwnPropertyDescriptor()、getPrototypeOf()、isExtensible()、ownKeys()、preventExtensions()、setPrototypeOf()。

4.Proxy.revocable()方法返回一个可取消的Proxy实例,写法为let {proxy,revoke} = Proxy.revocable(target,handler),使用revoke()就收回代理权。

5.虽然Proxy可以代理针对目标对象的访问,但它不是目标对象的透明代理。主要原因是在代理情况下,目标对象内部的this关键字会指向Proxy代理。使用this绑定原始对象可以解决这个问题。

6.Proxy对象可以拦截目标对象的任意属性,这使得它很适合用来编写Web服务的客户端。

 

第13章 Reflect

1.Reflect对象与Proxy对象一样,也是为了操作对象而提供的新的API。

2.Reflect的设计目的是将Object对象的一些属于语言内部的方法放到Reflect对象上;修改某些Object方法的返回结果让其变得更合理;让Object操作都变成函数行为;在Reflect上获取默认行为。

3.Reflect对象一共有13个静态方法,为:Reflect.get()、Reflect.set()、Reflect.has()、Reflect.deleteProperty()、Reflect.construct()、Reflect.getPrototypeOf()、Reflect.setPrototypeOf()、Reflect.apply()、Reflect.defineProperty()、Reflect.getOwnPropertyDescriptor()、Reflect.isExtensible()、Reflect.preventExtensions()、Reflect.ownKeys()。

4.Reflect.set()方法会被Proxy.defineProperty()拦截。

5.Reflect.ownKeys方法用于返回对象的所有属性,基本等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和。

6.使用Proxy可以实现观察者模式。观察者模式指的是自动观察数据对象的模式,一旦对象有变化,函数就会自动执行。

 

第14章 Promise对象

1.Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大。

2.Promise对象的状态不受外界影响,有3种状态:Pending、Fulfilled、Rejected。一旦状态改变就不会再变,任何时候都可以得到这个结果。

3.Promise对象是一个构造函数,用来生成Promise实例,它接受一个函数作为参数,该函数的两个参数分别是resolve和reject。

4.Promise新建后就会立即执行,then方法指定的回调函数将在当前脚本所有同步任务执行完成后才会执行。

5.Promise实例具有then方法,then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。

6.Promise.prototype.catch方法是.then(null,rejection)的别名,用于指定发生错误时的回调函数。

7.Promise.all方法用于将多个Promise实例包装成一个新的Promise实例,该方法接受一个数组作为参数,即var p = Promise.all([p1,p2,p3])。

8.只有p1、p2、p3的状态都变成Fulfilled,p的状态才会变成Fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

9.只要p1、p2、p3中有一个被Rejected,p的状态就变成Rejected,此时第一个被Rejected的实例的返回值会传递给p的回调函数。

10.var p = Promise.race([p1,p2,p3])中,只要p1、p2、p3中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值就传递给p的回调函数。

11.Promise.resolve()可以将现有对象转为Promise对象,如将jQ生成的deferred对象转为新的Promise对象。

12.setTimeout(fn,0)是在下一轮事件循环开始时执行的,Promise.resolve()在本轮事件循环结束时执行。

13.Promise.reject(reason)方法也会返回一个新的Promise实例,状态为Rejected。

14.我们可以自行部署done方法(总是处于回调链的尾端,保证抛出任何可能出现的错误)和finally方法(接受一个普通的回调函数作为参数,该函数不管怎样都必须执行)。

15.Promise.try()可以让同步函数同步执行,让异步函数异步执行。

 

第15章 Iterator和for...of循环

1.任何数据结构,只要部署Iterator接口,就可以完成遍历操作。

2.Iterator的作用有3个:一是为各种数据结构提供一个统一的、简便的访问接口;二是使得数据结构的成员能按某种次序排列;三是创造了一种新的遍历命令——for...of循环,Iterator接口主要供for...of消费。

3.对于遍历器对象(指针对象),每次调用next方法都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。

4.数据结构只要部署了Iterator接口,我们就称这种数据结构是可遍历的。默认的Iterator接口部署在Symbol.iterator属性。

5.原生具备Iterator接口的数据结构如下:Array、Map、Set、String、TypedArray、arguments、NodeList。

6.在解构赋值、扩展运算符、yield*、所有任何接受数组作为参数的场合会默认调用Symbol.iterator方法。

7.Symbol.iterator方法的最简单实现是Generator函数。

8.遍历器对象除了具有next方法,还可以具有return方法(for..of循环提前退出,就会调用)和throw方法(配合Generator函数使用)。

9.for...of循环可以使用的范围包含数组、Set和Map结构、类数组对象、Generator对象和字符串。

10.如果要通过for...of循环获取数组的索引,可以借助数组实例的entries方法和keys方法。

11.对字符串来说,for...of循环有一个特点,就是可以正确识别32位UTF-16字符。

12.forEach循环无法中途跳出,for...of则可以,而且与for...in一样简洁,而没有for...in的缺点,提供了遍历所有数据结构的统一操作接口。

 

第16章 Generator函数的语法

1.Generator函数是ES6提供的一种异步编程解决方案,可以把它理解成一个状态机,封装了多个内部状态,执行Generator函数会返回一个遍历器对象。

2.Generator函数只有调用next方法时才会执行,yield表达式只能用在Generator函数里面,用在其他地方都会报错。

3.yield表达式如果用在另一个表达式之中,必须放在圆括号里面。

4.yield表达式用作函数参数或放在赋值表达式的右边,可以不加括号。

5.由于Generator函数就是遍历器生成函数,因此可以把Generator赋值给对象的Symbol.iterator属性,从而使得该对象具有Iterator接口。

6.yield语句本身没有返回值,或者说总是返回undefined。next方法可以带有一个参数,该参数会被当作上一条yield语句的返回值。

7.for...of循环、扩展运算符、解构赋值、Array.from方法内部调用的都是遍历器接口。这意味着,它们都可以将Generator函数返回的Iterator对象作为参数。

8.Generator函数返回的遍历器对象都有一个throw方法,可以在函数体外抛出错误,然后在Generator函数体内捕获。

9.throw命令和g.throw方法是无关的,两者互不影响。

10.一旦Generator执行过程中抛出错误,就不会再执行下去了。如果此后还调用next方法,将返回一个value为undefined、done为true的对象。

11.Generator函数返回的遍历器对象还有一个return方法,可以返回给定的值,并终结Generator函数的遍历。

12.如果Generator函数内部有try...finally代码块,那么return方法会推迟到finally代码块执行完再执行。

13.yield*语句用来在Generator函数里面执行另一个Generator函数,等同于使用for...of循环展开。

14.Generator函数总是返回一个遍历器,这个遍历器是Generator函数的实例,它也继承了Generator函数的prototype对象上的方法。

15.我们可以使用call方法绑定Generator函数内部的this,再把生成器改造成构造函数,就可以对它使用new命令了。

16.Generator是实现状态机的最佳结构,无需使用用来保存状态的外部变量。

17.Generator函数是ES6对协程的实现,但属于不完全实现。我们可以将多个任务写成Generator函数,它们之间用yield语句交换控制权。

18.Generator的应用场景:异步操作的同步化表述、控制流管理、部署Iterator接口、作为类数组数据结构。

 

第17章 Generator函数的异步应用

1.ES6诞生以前,异步编程的方法大概有下面4种:回调函数、事件监听、发布/订阅、Promise对象,Generator函数将js异步编程带入了一个全新的阶段。

2.Node约定回调函数的第一个参数必须是错误对象err。

3.回调函数嵌套使得代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理,多个异步操作形成了强耦合,称为回调函数地狱。

4.为了解决回调地狱,Promise对象被提出,它允许将回调函数的嵌套写成链式调用。但是Promise导致代码冗余,一眼看去都是then的堆积,语义不清。

5.协程意思是协同程序,指多个线程之间互相协作,完成异步任务。

6.Generator函数是协程在ES6中的实现,最大特点就是可以交出函数的执行权。

7.Generator函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。除此之外,它还有两个特性使它可以作为异步编程的完整解决方案:函数体内外的数据交换和错误处理机制。

8.Thunk函数是自动执行Generator函数的一种方法。编译器的传名调用是将参数放到一个临时函数之中,再将这个临时函数传入函数体,这个临时函数就成为Thunk函数。

9.Thunk函数将多参数函数替换成一个只接受回调函数作为参数的单参数函数,即柯里化。任何函数,只要参数有回调函数,就能写成Thunk函数的形式。

10.生产环境中转换器建议使用Thunkify模块。

11.Thunk函数可以用于Generator函数的自动流程管理,使得Generator函数可以自动执行,即用递归来自动完成这个过程。

12.co模块用于Generator函数的自动执行。co的前提条件是,Generator函数的yield命令后面只能是Thunk函数或Promise对象。

13.co支持并发的异步操作,需要把并发的操作都放在数组或对象里面,跟在yield语句后面。

 

第18章 async函数

1.async函数是Generator函数的语法糖,async函数就是将Generator函数的星号替换成async,将yield替换成await,仅此而已。

2.Generator函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。

3.async函数有更好的语义、更广的适用性。

4.async函数返回值是Promise对象。

5.async函数内部抛出错误会导致返回的Promise对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

6.正常情况下,await命令后面是一个Promise对象。如果不是,会被转成一个立即resolve的Promise对象。

7.await命令后面的Promise对象的运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。

8.多个await命令后面的异步操作如果不存在继发关系,最好让它们同时触发。

9.await命令只能用在async函数之中,如果用在普通函数中就会报错。

10.如果确实希望多个请求并发执行,可以使用Promise.all方法。

11.async函数的实现原理就是将Generator函数和自动执行器spawn函数包装在一个函数里。

12.Promise取代了回调函数,但是失了语义;Generator函数语义比Promise清晰,而async函数最简洁,最符合语义。

13.目前有一个提案,为异步操作提供原生的遍历器接口,即value和done两个属性都是异步产生的,这成为异步遍历器。

14.异步遍历器最大的语法特点就是,调用遍历器的next方法返回的是一个Promise对象。

15.对象的异步遍历器接口部署在Symbol.asyncIterator属性上面。

16.for...of循环用于遍历同步的Iterator接口,for await...of循环用于遍历异步的terator接口。

17.异步Generator函数的作用是返回一个异步遍历器对象。在语法上,异步Generator函数是async函数与Generator函数的结合。

18.yield*语句也可以与一个异步遍历器一同使用。

 

第19章 Class的基本语法

1.ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到。

2.Object.assign方法可以很方便地一次向类添加多个方法。

3.类的内部定义的方法都是不可枚举的。这点与ES5的行为不一致。

4.类和模块内部默认使用严格模式。考虑到未来所有的代码都是运行在模块之中,所以ES6实际上已经把整个语言都升级到严格模式下。

5.类的所有实例共享一个原型对象。如p1和p2都是Point的实例,则它们的原型都是Point.prototype。

6.与函数一样,Class也可以使用表达式的形式定义。

7.类不存在变量提升,以保证子类在父类之后定义。

8.私有方法可以通过变通方法来模拟实现,一种做法是在命令上加下划线,另一种方法是索性将私有方法移除模块,还有一种方法是利用Symbol值的唯一性将私有方法的名字命名为一个Symbol值。

9.私有属性可以用#表示,也可以用来编写私有方法。

10.解决this的指向问题可以通过在构造方法中绑定this,或者使用箭头函数或Proxy。

11.setter和getter函数是设置在属性的Descriptor对象上的。

12.如果在一个方法前加上static关键字,就是静态方法,静态方法也可以从super对象上调用。

13.ES6为new命令引入了new.target属性,返回new命令所作用的构造函数。如果构造函数不是通过new命令调用的,那么new.target会返回undefined。

14.在函数外部,使用new.target会报错。

 

第20章 Class的继承

1.Object.getPrototypeOf方法可以用来从子类上获取父类。

2.super这个关键字既可以当函数用,也可以当对象用。

3.由于绑定子类的this,因此如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性。

4.B.__proto__ = A,B.prototype.__proto__ = A.prototype。

5.若p2是子类的实例,p1是父类的实例,则p2.__proto__.__proto__ = p1.__proto__。

6.以前,原生构造函数是无法继承的。ES6可以自定义原生数据结构的子类,这是ES5无法做到的。

 

第21章 修饰器

1.修饰器是一个函数,用来修改类的行为,目前Babel转码器已经支持。修饰类的时候,参数target就是会被修饰的类。

2.修饰器不仅可以修饰类,还可以修饰类的属性。

3.修饰类的属性时,修饰器函数一共可以接受3个参数,第一个参数是所要修饰的目标对象,第二个参数是所要修饰的属性名,第三个参数是该属性的描述对象。

4.修饰器有注释的作用。

5.如果同一个方法有多个修饰器,那么该方法会从外到内进入修饰器,然后由内向外执行。

6.修饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。类是不会提升的。

7.如果一定要修饰函数,可以采用高阶函数(包装)的形式直接执行。

8.core-decorators.js是一个第三方模块,提供了@autobind、@readonly、@override、@deprecated、@suppressWarnings等常见修饰器。

9.我们可以使用修饰器使得对象的方法被调用时自动发出一个事件。

10.在修饰器的基础上可以实现Mixin模式。所谓Mixin模式,就是对象继承的一种替代方案,意为在一个对象中混入另外一个对象的方法。

11.通过Object.assign方法可以简单实现Mixin模式。

12.Trait也是一种修饰器,效果与Mixin类似,但是提供了更多的功能,比如防止同名方法冲突、排除混入某些方法、为混入的方法起别名等。

13.使用绑定运算符(::)可以配合excludes、alias、as使用。

 

第22章 Module的语法

1.CommonJS用于服务器,AMD用于浏览器。ES6在语言规格层面上实现了模块功能,而且实现得相当简单,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。

2.CommonJS和AMD是运行时加载;ES6 Module是编译时加载,可以进行静态优化。

3.ES6的模块自动采用严格模式。

4.export命令后面使用大括号指定所要输出的一组变量,import命令接受一个对象(用大括号表示)。

5.exort语句输出的接口与其对应的值是动态绑定关系,即通过该接口可以取到模块内部实时的值。

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

7.如果多次重复执行同一句import语句,那么只会执行一次。

8.可以使用整体加载(即星号)lai指定一个对象,所有输出值都加载在这个对象上。

9.为了方便用户,使其不用阅读文档就能加载模块,可以使用export default命令为模块指定默认输出。这时import命令和export default命令后面不使用大括号。

10.一个模块只能有一个默认输出,因此export default命令只能用一次。

11.export和import语句可以结合在一起写成一行。

12.模块之间也可以继承。

13.如果要使用的常量非常多,可以建立一个专门的constants目录,将各种常量写在不同的文件里面并保存在该目录下。

14.import()函数可以完成动态加载,返回一个Promise对象,可用于按需加载、条件加载、动态路径的场景。

 

第23章 Module的加载实现

1.默认情况下,浏览器同步加载js脚本,即渲染引擎遇到<script>标签就会停下来,等到脚本执行完毕再继续向下渲染。如果是外部脚本,还必须加入脚本下载的时间。

2.浏览器允许脚本异步加载,<script>标签打开defer或async属性,脚本就会异步加载。

3.defer属性是渲染完执行,async属性是下载完就执行。如果有多个defer脚本,则会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

4.浏览器加载ES6模块时也使用<script>标签,但是要加入type="module"属性,等同于打开了<script>标签的defer属性。

5.在模块中,顶层this关键字返回undefined,而不是指向window。

6.CommonJS是值复制,ES6模块是值引用;CommonJS模块是运行时加载,ES6模块是编译时输出接口。

7.import命令可以加载CommonJS模块,require命令可以加载ES6模块。

8.循环加载指的是a脚本的执行依赖b脚本,而b脚本的执行又依赖a脚本。

9.ES6模块的循环依赖做得比CommonJS好。

10.ES6模块的转码可以通过es6-module-transpiler或SystemJS垫片库实现。

11.System.import使用异步加载,返回一个Promise对象,所以可以使用then方法指定回调函数。

 

第24章 编程风格

1.用let完全取代var;const定义常量,在多线程中有利于线程安全。

2.静态字符串一律使用单引号或反引号,不使用双引号。

3.对数组或对象的成员赋值时,优先使用解构赋值。

4.单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。

5.对象尽量静态化,一旦定义就不得随意添加新属性。如果添加新属性不可避免,要使用Object.assign方法。

6.如果对象的属性名是动态的,可以在创造对象时使用属性表达式定义。

7.使用扩展运算符复制数组,使用Array.from方法将类数组对象转为数组。

8.立即执行函数可以写成箭头函数的形式。简单函数建议采用箭头函数,函数体复杂的函数应采用传统的函数写法。

9.不要在函数体内用arguments变量,使用rest运算符(...)代替。

10.总是用class取代需要prototype的操作。

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

 

第25章 读懂ECMAScript规格

1.规格文件是计算机语言的官方标准,详细描述了语法规则和实现方法。如果遇到疑难的语法问题,实在找不到答案,也可以去查看规格文件,了解语言标准是怎么说的。规格文件是解决问题的“最后一招”。

2.0==null是false。

3.数组的空位会反映在length属性。空位有自己的位置,但是这个位置未定义,即这个值是不存在的。

4.数组的map方法会跳过空位。

5.V8引擎是JS的编译器。

 

第26章 ArrayBuffer

1.ArrayBuffer对象、TypedArray视图和DataView视图是js操作二进制数据的一个接口。它们都以数组的语法处理二进制数据,所以统称为二进制数组。

2.二进制数组由三类对象组成:ArrayBuffer对象(代表内存中一段二进制数据,可以通过视图进行操作)、TypedArray视图(共包括9种类型的视图)、DataView视图(可以自定义复合格式的视图,还可以自定义字节序)。

3.ArrayBuffer对象代表原始的二进制数据,TypedArray视图用于读写简单类型的二进制数据,DataView视图用于读写复杂类型的二进制数据。

4.二进制数组应用场景为:File API、Fetch API、AJAX、Canvas、WebSockets。

5.TypedArray视图的构造函数除了接受ArrayBuffer实例作为参数,还可以接受普通数组作为参数,直接分配内存生成底层的ArrayBuffer实例,同时完成对这段内存的赋值。

6.TypedArray的构造函数为TypedArray(buffer,byteOffset,length)、TypedArray(length)、TypedArray(typedArray)、TypedArray(arrayLikeObject)。

7.TypedArray和普通数组可以相互转化,普通数组的操作方法和属性(除了concat方法)对TypedArray数组完全适用。

8.x86体系的计算机都采用小端字节序,相对重要的字节排在后面的内存地址,很多网络设备采用的是大端字节序。

9.与普通数组相比,TypedArray数组的最大优点就是可以直接操作内存,不需要数据类型转换,所以速度快得多。

10.ArrayBuffer与字符串可以进行相互转换。

11.Uint8ClampedArray视图的溢出规则为:凡是发生正向溢出,该值一律为255,如果发生负向溢出,该值一律为0。

12.TypedArray的实例有buffer、byteLength、byteOffset、length属性,有set、subarray、slice方法,还有TypedArray.of()、TypedArray.from()方法。

13.由于视图的构造函数可以指定起始位置和长度,所以在同一段内存中可以依次存放不同类型的数据,这叫做复合视图。

14.默认情况下,DataView的get方法使用大端字节序解读数据,如果需要使用小端字节序解读,必须在get方法的第二个参数指定true。

15.js是单线程的,Web Worker引入了多线程;主线程用来与用户互动,Worker线程用来承担计算任务。每个线程的数据都是隔离的,通过postMessage()通信。

16.SharedArrayBuffer允许Worker线程与主线程共享同一块内存。SharedArrayBuffer的API与ArrayBuffer一模一样,唯一的区别是后者无法共享。

17.SharedArrayBuffer API提供Atomics对象,保证所有共享内存的操作都是原子性的,并且可以在所有线程内同步。

18.Atomics对象提供store、load、wait、wake、add、sub、and、or、xor方法,还有compareExchange、exchange、isLockFree方法。

 

posted @ 2022-01-02 14:41  罗毅豪  阅读(247)  评论(0编辑  收藏  举报