Chapter 2:let 和 const 命令
-
使用
Object.freeze方法冻结const常量:const foo = Object.freeze({}) foo.prop = 123 // It doesn't work. 在全局作用域声明的
let/const不会被绑定到全局变量上。
Chapter 3:变量的解构赋值
-
事实上,只要某种数据结构具有
Iterator接口,都可以采用数组形式的解构赋值:function* fibs () { var a = 0 var b = 1 while (true) { yield a [a, b] = [b, a + b] } } var [first, second, third, fourth, fifth, sixth] = fibs() let {foo, bar} = {foo: 1, bar: 2}是let {foo: foo, bar: bar} = {foo: 1, bar: 2}的简写。-
嵌套结构对象的解构:
var obj = { p: [ 'Hello', { y: 'world' } ] } var {P: [x, { y }]} = obj // 会得到 x, y 的值,但不会得到 p ,因为 p 是模式,不是变量。let obj = {} let arr = [] ({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true }) // 加 () 是为了避免 JS 将 {} 理解为代码块,而发生语法错误。 解构的默认值生效的条件是属性值严格等于
undefined。(用null也不行。)-
如果解构的是嵌套对象,子对象所在的父属性不存在,那么会报错:
var {foo: {bar}} = {baz: 'baz'} -
字符串也支持解构赋值:
const [a, b, c, d, e] = 'hello' // h, e, l, l, o const { length: len } = 'hello' // 5 -
数值和布尔值的解构赋值:
let { toString: s } = 123 s === Number.prototype.toString // true let { toString: s2 } = true s2 === Boolean.prototype.toString // true -
关于圆括号的规则:[P025 - 026]
- 变量声明语句中,模式不能带有圆括号
- 函数参数中,模式不能带有圆括号
- 不能将整个模式或嵌套模式中的一层放在圆括号中
-
遍历
Map:for(let [key, value] of map) { }
Chapter 4:字符串的扩展
-
ES6之前,超过 \uFFFF 的 Unicode 字符,要使用 2 个双字节形式表达。ES6 中,只要将码点放入大括号就能正确解读该字符:
\u{41}\u{42} \\ AB '\u{1F680}' === '\uD83D\uDE80' // true ES6 提供了
codePointAt处理 4 字节储存的字符,返回一个字符的码点。不过要配合for...of循环解决位置序号的问题。String.fromCharCode()用于从码点返回对应字符,但是不能识别 32 位的 UTF-16 字符( Unicode 编号大于 0xFFFF )�。String.fromCodePoint()解决了这个问题。ES6 提供了
at()方法解决charAt无法正确返回大于 0xFFFF 的字符的问题。-
JavaScript 将合成字符视为两个字符(比如带注音符号的字符)。使用
normalize()方法解决这个问题,具体用法查阅手册:'\u01D1\.normalize() === '\u004F\u030C'.normalize() repeat(n)用来将指定字符串重复 n 次,n 为小数的话,会被阶段取整,n 为负数或 Infinity 会报错。-
ES7 提供了字符串补全长度的功能。如果某个字符串未达到指定长度,会在头部或尾部补全。
padStart()作用于头部,padEnd()于尾部。'x'.padEnd(5, '123') -
标签模板:本质是一个函数,字符串模板会被拆分开并当做参数传入函数中:[P040 - P041]
function tag (stringArr, ...vaules) { console.log(stringArr) for(let i of values) { console.log(values) } } tag`Hello ${1 + 2} world ${3 + 4}` /* arg1: ['Hello ', ' world', ''] arg2: 3 arg3: 7 */// 过滤 HTML 字符串 var message = SafeHTML`<p>${sender} has sent you a message.</p>` function SafeHTML (templateData) { var s = templateData[0] for (var i = 1; i < arguments.length; i++) { var arg = String(arguments[i]) s += arg.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') s += templateData[i] } return s }标签模板还可以用于 i18n 和 JSX 函数。
可以通过
String.raw()方法取得转义前的字符串。它会替换所有变量,并转义反斜线。[�P042]
Chapter 5: 正则的扩展
[P43-48]
Chapter 6: 数值的扩展
ES6 提供了二进制和八进制数值的新写法,分别用前缀
0b或0B和0o或0O表示。(从 ES5 开始,八进制数就已经不再允许使用前缀 0 直接表示了。)-
ES6 引入了一个非常小的常量:
Number.EPSILON。它的作用是为浮点数计算设置一个误差范围:0.1 + 0.2 - 0.3 === 0 // false 0.1 + 0.2 - 0.3 < Number.EPSILON // true ES6 引入了
Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER两个常量,用来表示整数范围的上下限。同时,可以使用Number.isSafeInteger()来加以判断,但是结果不一定可靠。[P051 - 052]ES6 为
Math进行了一些扩展。具体可以查看文档。[P54 - 58]-
ES6 新增了指数运算符(
**):2 ** 3 === 8 let b = 3 b **= 3 // 27
Chapter 7:数组的扩展
-
Array.from()用来将类似数组的对象或可遍历的对象转换成数组:[P060 - 061]let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 } let arr = Array.from(arrayLike)function foo () { var args = Array.from(arguments) }同时,扩展运算符(
...)也可以将某些数据结构转为数组。function foo () { var args = [...arguments] }const doms = [...documents.querySelectorAll('div')]只有对象部署了
Symbol.iterator接口,才可以进行转换。同时,Array.from()也支持类似数组的对象。所谓类似数组的对象,本质特征只有一点:具有length属性。 -
Array.of()用来将一组值转换为数组:Array.of(1, 2, 3) -
copyWithin()用来将当前数组内部指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。(会修改当前数组)Array.prototype.copyWithin(target, start = 0, end = this.length)[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5] find()用于找出第一个符合条件的数组成员;findIndex()返回第一个符合条件的数组成员索引。(使用方法与filter类似)�-
fill()方法用于使用指定值填充数组:['a', 'b', 'c'].fill(7) // [7, 7, 7] -
entries(),keys()&values():遍历键值对、键名、键值。for (let index of ['a', 'b'].keys()) for (let el of ['a', 'b'].values()) for (let [index, el] of ['a', 'b'].entries()) includes()不会像indexOf()一样使用===而导致对 NaN 的误判。Map的has()方法用来查找键名,Set的has()方法用来查找键值。-
数组的空位并不等于
undefined。undefined也是值,会占据数组的位置:[P065 - 066]0 in [undefined, undefined, undefined] // true 0 in [, ,] // false在 ES5 中,不同函数对数组空位的处理很不一样。而 ES6 统一视为
undefined。 -
数组推导:(注意控制内存消耗)[P067 - 068]
var a1 = [1, 2, 3, 4] var a2 = [for (i of a1) => i * 2] var a3 = [for (i of a1) => if(i < 3) i]
Chapter 8:函数的扩展
对函数指定默认值之后,函数的
length属性会返回没有指定默认值的参数个数。利用参数默认值,可以指定某一个参数不得省略(指定其默认值为一个函数,这个函数会抛出一个异常)
ES6 引入了 rest 参数(
...args),用于获取函数的多余参数。rest 参数之后不能再有其他参数。数组的扩展运算符能够正确识别 32 位 Unicode 字符。
-
任何类似数组的对象,或者有
Iterator接口的对象都可以使用扩展运算符,比如Generator:var go = function* () { yield 1 yield 2 yield 3 } [...go()] -
函数的
name属性的行为,在 ES6 中有了变化:[P079 - 080]var func = function () { console.log('hello') } console.log(func.name) // ES5: "" // ES6: "func" const bar = function baz() {} console.log(bar.name) // ES5: "baz" // ES6: "baz" (new Function).name // "anonymous" -
箭头函数:
箭头函数不能用作构造函数。
不可以使用
arguments对象(如果外部是一个function,会访问到外部function的arguments)�。不可以使用
yield命令,故不能作为Generator函数。-
pipeline
const pipeline = (...funcs) => val => funcs.reduce((a, b) => b(a), val) const plus1 = a => a + 1 const mult2 = a => a * 2 const addThenMult = pipeline(plus1, mult2) addThenMult(5) lambda 演算
-
ES7 提出了函数绑定运算符(
::),用来替代bind()之类的函数:[P084 - 085]foo::bar // 等价于 bar.bind(foo) foo::bar(...args) // 等价于 bar.apply(foo, args)如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上:
::obj.foo // 等价于 obj.foo.bind(obj) 尾调用优化和尾递归[P086 - 087]
ES7 提案允许函数函数的最后一个参数有尾逗号( trailing comma )。
Chapter 9:对象的扩展
/*
Why this happens?
Guess: JavaScript Scope
*/
var obj = {
data: '123',
getData () {
console.log(this.data)
}
}
obj.getData() // 123
var obj2 = {
data: '123',
getData: () => {
console.log(this.data)
}
}
obj2.getData() // undefined
-
对象中的 Generator 函数:
var obj = { * m () { yield 'Hello World!' } } -
属性表达式与简洁表示法不能一起使用:
var foo = 'bar' var bar = 'abc' var baz = { [foo] } // Error bind方法创造的函数,name属性返回bound加上原函数的名字,Function构造函数创造的函数,name属性返回anonymous;如果对象方法是一个Symbol值,则返回这个Symbol值的描述。Object.is()用来判断两个值是否严格相等。它与===的行为基本一致。有两点不同:+0不等于-0,NaN等于自身。Object.assign()只复制可枚举的自有属性,而且是浅拷贝。Object.setPropertyOf()和Object.getPropertyOf()用来操作__proto__。Object.entries()可以用来将一个对象转为真正的 Map 结构:const map = new Map(Object.entries(obj))rest 参数 / 扩展运算符(
...)用于从一个对象取值。需要注意的是,rest 参数的复制是浅复制,对于复合类型得到的是引用,而不是副本。同时,rest 参数不会复制继承自原型对象的属性。-
Null 传导运算符 —— 用于安全访问对象内部的属性。
const firstName = message?.body?.user?.firstName || 'default'有四种用法:
obj?.prop,obj?.[prop],func?.(...args),new C?.(...args)。可以组合使用。