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)
。可以组合使用。