《ECMAScript 6 入门》读书笔记(一)
《ECMAScript 6 入门》是一本 JavaScript 语言教程,全面介绍 ECMAScript 6 新引入的语法特性。作者阮一峰大佬慷慨地选择将全书开源:ECMAScript 6 入门。将知识点简便地总结一下,以供后续使用时参考或复习。
此博文包括:let 和 const 命令、变量的解构赋值、字符串的扩展、正则的扩展、数值的扩展、数组的扩展。
let和const命令
1.let
:let
声明的变量仅在块级作用域内有效。不存在变量提升;存在暂时性死区,只能在声明的位置后面获取和使用;相同作用域内不可重复声明。
2.块级作用域:外层作用域无法读取内层作用域的变量,内层作用域可以定义外层作用域的同名变量。
3.根据ES 6附录B的规定,在浏览器的ES 6环境中,块级作用域内声明的函数,行为类似于var
声明的变量。应避免在块级作用域内声明函数,或用函数表达式代替函数声明语句。
4.do 表达式:在块级作用域之前加上do
,使其变为表达式(可以返回值)。
1 | // 变量x得到整个块级作用域的返回值 |
5.const
:声明一个只读常量。一旦声明,就必须立即初始化。和let
一样,只在声明所在的块级作用域内有效;声明的常量不提升;存在暂时性死区;不可重复声明。
const
保证变量指向的内存地址不可改动。因此将对象声明为常量时,不可变的只是地址,对象本身可变,可以为其添加新属性。
如果真想将对象冻结,应用Object.freeze()
方法(对象本身和 其属性都应冻结)。
1 | var constantize = (obj) => { |
6.顶层对象的属性:let
、const
、class
声明的全局变量不属于顶层对象的属性。
补充资料:ES6之”let”能替代”var”吗?
变量的结构赋值
1.解构:按照一定模式,从数组和对象中提取值,对变量进行赋值。解构不成功,变量的值就等于undefined
。
1 | let [foo, [[bar], baz]] = [1, [[2], 3]]; |
2.不完全解构:等号左边的模式,只匹配一部分的等号右边的数组。
1 | let [x, y] = [1, 2, 3]; |
只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
3.解构赋值允许指定默认值。ES6 内部使用严格相等运算符(===
),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined
,默认值不会生效。
1 | let [foo = true] = []; |
如果默认值是一个表达式,那么这个表达式是惰性求值的(用到时才会求值)。
1 | // x能取到值,所以函数f根本不会执行 |
4.要将一个已经声明的变量用于解构赋值时,将大括号写在行首会导致JavaScript引擎将其解释为代码块,从而发生语法错误。
1 | let x; |
对象的结构赋值
5.对象的解构:属性没有次序,变量取值由名称决定。
1 | let { bar, foo} = { foo: "aaa", bar: "bbb" }; |
如果变量名与属性名不一致,须写成:
1 | var { foo: baz} = { foo: 'aaa', bar: 'bbb'}; |
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
6.解构也可用于嵌套结构的对象。
1 | let obj = { |
字符串的结构赋值
7.此时字符串被转化成一个类似数组的对象,且具有length
属性(可以针对此属性解构赋值)。
1 | const [a, b, c, d, e] = 'hello'; |
数值、布尔值的结构赋值
8.解构赋值的规则:只要等号右边的值不是对象或数组,就先将其转为对象。undefined
和null
无法转为对象,所以对它们解构赋值都会报错。
1 | let {toString: s} = 123; |
函数参数的结构赋值
9.为函数move
的参数指定默认值:
1 | function move({x = 0, y = 0} = {}) { |
为变量x
和y
指定默认值:
1 | function move({x, y} = {x: 0, y:0}){ |
圆括号问题
10.ES6规定,只要可能导致解构歧义,就不得使用圆括号。由于这条规则不易辨别,因此建议尽量不要在模式中放置圆括号。
11.以下三种解构赋值不得使用圆括号。
- 变量声明语句中,不能带有圆括号。
- 函数参数中,模式不能带有圆括号。
- 赋值语句中,不能将整个模式,或嵌套模式中的一层,放在圆括号之中。
12.可以使用圆括号的情况:赋值语句的非模式部分,可以使用圆括号。
用途
- 交换变量的值:
1 | let x = 1; |
- 从函数中返回多个值:将返回的数组或对象中的值取出
- 函数参数的定义:方便地将无序的参数与变量名对应
- 提取JSON数据:
1 | let jsonData = { |
- 函数参数的默认值
- 遍历Map结构:
1 | var map = new Map(); |
- 输入模块的指定方法
1 | const { SourceMapConsumer, SourceNode } = require("source-map"); |
字符串的扩展
1.字符的Unicode表示法:将码点放入大括号。
1 | "\u{20BB7}" // "𠮷" |
2.新增一些方法:
codePointAt()
:能够正确处理4个字节储存的字符,返回一个字符的码点。是测试一个字符由两个字节还是由四个字节组成的最简单方法。String.fromCodePoint()
:用于从码点返回对应字符,可识别Unicode编号大于0xFFFF的码点(32位的UTF-16字符)。at()
(提案):返回字符串给定位置的字符,可识别Unicode编号大于0xFFFF的码点。repeat(n)
:返回一个新字符串,表示将原字符串重复n次。normalize()
:将字符的不同表示方法统一为同样的形式,这称为Unicode正规化。includes()
:返回布尔值,表示是否找到了参数字符串。startsWith()
:返回布尔值,表示参数字符串是否在源字符串的头部。endsWith()
:返回布尔值,表示参数字符串是否在源字符串的尾部。padStart()
:如果某个字符串不够指定长度,会在头部补全。第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串(默认为空格)。padEnd()
:同上,用于尾部补全。
3.模版字符串:常用于定义多行字符串,或者在字符串中嵌入变量。用反引号(`)标识。
1 | // 普通字符串 |
模板字符串中嵌入变量,要将变量名卸载${}
中。大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性,也可以调用函数。
如果大括号中的值不是字符串,将按照一般的规则转为字符串(例如对象调用toString
方法)。
4.标签模板(功能):函数调用的一种特殊形式。模板字符串作为参数紧跟在一个函数名后,该函数被调用以处理该模板字符串。常用于转义特殊字符和多语言转换(国际化处理)。
1 | console.log`Kyon` |
模板字符有变量时,先把模板字符串处理成多个参数。处理得到的第一个参数是一个数组,包含那些没有变量替换的部分。
1 | var a = 5; |
模板处理函数的第一个参数(模板字符串数组),还有一个raw
属性,保存转义后的原字符串。
5.String.raw()
:返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对应于替换变量后的模板字符串;如果原字符串的斜杠已经转义,则不会做任何处理。常用于处理模板字符串。
1 | String.raw`Hi\n${3+4}!`; |
也可作为正常函数使用,第一个参数应是具有raw
属性的对象,且raw
属性的值应是一个数组。
1 | String.raw({ raw: 'test' }, 0, 1, 2); |
6.模板字符串的限制(提案):放松对标签模板里面的字符串转义的限制。如果遇到不合法的字符串转义,就返回undefined,而不是报错,并且从raw
属性上面可以得到原始字符串。
正则的扩展
1.u
修饰符:Unicode 模式,用来正确处理大于\uFFFF
的 Unicode 字符。对于码点大于\uFFFF
的 Unicode 字符,点字符(.
,除了换行符外的任意单个字符)、Unicode 字符表示法(使用大括号表示 Unicode 字符)、量词、预定义模式(\S
,匹配所有不是空格的字符)必须加上u
修饰符才能识别。
1 | /^\uD83D/u.test('\uD83D\uDC2A') |
2.y
修饰符:“粘连”修饰符,全局匹配,但须确保匹配必须从剩余的第一个位置开始。一个应用是从字符串提取 token(词元),y
修饰符确保了匹配之间不会有漏掉的字符。
1 | var s = 'aaa_aa_a'; |
3.ES 6 的正则对象新增了sticky
属性和flags
属性,分别表示是否设置了y
修饰符以及返回正则表达式的修饰符。
1 | var r = /hello\d/y; |
4.有一些提案。因为我暂时对正则不太熟悉,所以略过。
数值的扩展
1.二进制、八进制表示法:分别用前缀0b
(或0B
)和0o
(或0O
)表示。用Number()
方法将其转化为十进制。
1 | 0b111110111 === 503 // true |
2.新增 Number 对象上的一些方法:
Number.isFinite()
:用于检查一个数值是否为有限的。Number.isNaN()
:用于检查一个值是否为NaN
。
与传统的全局方法isFinite()
和isNaN()
的区别在于,传统方法先调用Number()
将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,非数值一律返回false
。
- 将全局方法
parseInt()
和parseFloat()
移植到 Number 对象上,行为完全保持不变,目的是逐步减少全局性方法,使得语言逐步模块化。 Number.isInteger()
:用于判断一个值是否为整数。在 JavaScript 内部,整数和浮点数是同样的储存方法,这个方法都会返回 true。
3.Number.EPSILON
:极小的常量,表示一个可以接受的误差范围。浮点数计算误差小于Number.EPSILON
时可以认为得到正确结果。
4.Number.isSafeInteger()
:JavaScript 能够准确表示的整数范围在-2^53
到2^53
之间(不含两个端点),超过这个范围的值无法精确表示。Number.MAX_SAFE_INTEGER
和Number.MIN_SAFE_INTEGER
这两个常量用来表示这个范围的上下限。Number.isSafeInteger()
则是用来判断一个整数是否落在这个范围之内。
5.Math 对象的扩展:所有新增方法都是静态方法,只能在 Math 对象上调用。
Math.trunc()
:用于去除一个数的小数部分,返回整数部分。对于非数值内部使用Number
方法将其先转为数值;对于空值和无法截取整数的值,返回 NaN。Math.sign
方法用来判断一个数到底是正数、负数、还是零。它会返回五种值:参数为正数,返回+1;负数返回-1;0返回0;-0返回-0;其他值返回NaN。Math.cbrt
:用于计算一个数的立方根。
此外,还有一些对数方法和三角函数方法。
6.指数运算符(**
):
1 | 2 ** 2 // 4 |
数组的扩展
1.Array.from()
:将类数组对象(本质特征是有length
属性)和可遍历对象(部署了 Iterator 接口的数据结构,包括 ES 6新增的 Set 和 Map)转化为真正的数组。
1 | let arrayLike = { |
还可以接受第二个参数,作用类似于数组的map
方法,用来对每个元素进行处理,将处理后的值放入返回的数组;如果map
函数里面用到了this
关键字,还可以传入Array.from()
的第三个参数,用来绑定this
。
1 | Array.from(arrayLike, x => x * x); |
2.Array.of()
:返回参数值组成的数组(没有参数则返回空数组)。
1 | Array(3) // [, , ,] |
3.数组实例的copyWithin()
:在当前数组内部,将指定位置的成员复制到其他位置(覆盖原有成员),然后返回当前数组。
接受三个参数(都为数值,否则自动转换):
- target(必需):从该位置开始替换数据;
- start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
1 | Array.prototype.copyWithin(target, start = 0, end = this.length) |
4.数组实例的find()
和findIndex()
:
find()
用于找出第一个符合条件的数组成员。其参数为一个回调函数(可以接收三个参数:当前的值,当前的位置和原数组),所有数组成员依次执行该回调函数,直到找出第一个返回值为true
的成员,然后返回该成员,否则返回undefined
。
1 | [1, 4, -5, 10].find((n) => n < 0) |
findIndex()
类似,返回第一个符合条件的数组成员的位置,否则返回-1
。
5.数组实例的fill()
:用给定值填充一个数组。
1 | // 数组中原有的元素将被覆盖 |
6.数组实例的keys()
、values()
和entries()
:用于遍历数组。都返回一个遍历器对象,可以用for..of
循环进行遍历;区别为分别对键名、键值、键值对遍历。
1 | for(let index of ['a', 'b'].keys()){ |
7.数组实例的includes()
(属于ES 7 但 Babel 转码器已经支持):返回一个布尔值,表示某个数组是否包含给定的值。
1 | [1, 2, 3].includes(2); // true |
8.数组的空位:和undefined
不同,数组的空位没有任何值。ES 5 对空位的处理规则很不一致(大多数情况会忽略);而 ES 6 明确将空位转为undefined
。尽管如此,建议避免出现空位。
1 | Array(3) // [, , ,] |