ES6 —— ES12
原文链接:https://www.jianshu.com/p/2514a5080c29
ECMAScript 是一种由 Ecma
国际(前身为欧洲计算机制造商协会)通过 ECMA-262
标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为 JavaScript
或 JScript
,所以它可以理解为是 JavaScript
的一个标准,但实际上后两者是 ECMA-262
标准的实现和扩展。
ES6(ES2015)
-
let
和const
var let const 变量提升 √ × × 全局变量 √ × × 重复声明 √ × × 重新赋值 √ √ × 暂时性死区 × √ √ 块作用域 × √ √ 只声明不初始化 √ √ × 暂时性死区(
TDZ
):ES6
明确规定,如果区块中存在let
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。 -
类(
Class
)
在ES6
之前,如果我们要生成一个实例对象,传统的方法就是写一个构造函数,例子如下:function Person(name, age) { this.name = name this.age = age } Person.prototype.information = function () { return 'My name is ' + this.name + ', I am ' + this.age }
但是在
ES6
之后,我们只需要写成以下形式:class Person { constructor(name, age) { this.name = name this.age = age } information() { return 'My name is ' + this.name + ', I am ' + this.age } }
箭头函数(Arrow function)
函数参数默认值(Function parameter defaults)
模板字符串(Template string)
解构赋值(Destructuring assignment)
模块化(Module)
扩展操作符(Spread operator)
-
Promise
Promise
是ES6
提供的一种异步解决方案,比回调函数更加清晰明了。
所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
Promise
提供统一的API
,各种异步操作都可以用同样的方法进行处理。Promise
对象有以下两个特点:- 对象的状态不受外界影响。
Promise
对象代表一个异步操作,有三种状态:Pending
(进行中)、Resolved
(已完成,又称 Fulfilled)和Rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。 - 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise
对象的状态改变,只有两种可能:从Pending
变为Resolved
和从Pending
变为Rejected
。
缺点:首先,无法取消
Promise
,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。第三,当处于Pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。var promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }) promise.then(function(value) { // success }, function(error) { // failure })
Promise.all()
:用于将多个Promise
实例,包装成一个新的Promise
实例。只有这6个实例的状态都变成fulfilled
,或者其中有一个变为rejected
,才会调用Promise.all
方法后面的回调函数。Promise.race()
:将多个Promise
实例,包装成一个新的Promise
实例。var p = Promise.race([p1, p2, p3])
只要p1、p2、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的Promise
实例的返回值,就传递给p
的回调函数。-
Promise.resolve()
:将现有对象转为Promise
对象。Promise.resolve('foo') // 等价于 new Promise(resolve => resolve('foo'))
-
Promise. reject()
:将现有对象转为Promise
对象,该实例的状态为rejected
。var p = Promise.reject('出错了'); // 等价于 var p = new Promise((resolve, reject) => reject('出错了'))
done()
:总是处于回调链的尾端,保证抛出任何可能出现的错误finally()
:用于指定不管Promise
对象最后状态如何,都会执行的操作。它与done
方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。-
Promise.try()
:让同步函数同步执行,异步函数异步执行,并且让它们具有统一的API
const f = () => console.log('now'); Promise.try(f); console.log('next'); // now // next
- 对象的状态不受外界影响。
for…of
```
const array1 = ['a', 'b', 'c']
for (const element of array1) {
console.log(element)
}
```
for ... in ; for ... of 区别
* for ... in 获取的是对象的键名;for ... of 遍历获取的是对象的键值
* for ... in 会遍历对象的整个原型链,性能非常差,不推荐使用;而 for ... of 只遍历当前对象,不会遍历原型链
* 对于数组的遍历,for ... in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性);for ... of 只返回数组的下标对应的属性值
* 对于普通对象,没有部署原生的 iterator 接口,直接使用 for...of 会报错,也可以使用 Object.keys(obj) 方法将对象的键名生成一个数组,然后遍历这个数组
* forEach 循环无法中途跳出,break 命令或 return 命令都不能奏效;for...of 循环可以与 break、continue 和 return 配合使用,跳出循环
* for...in 循环主要是为了遍历对象而生,不适用于遍历数组;for...of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象
- Symbol
symbol
是一种基本数据类型,表示独一无二的值。Symbol()
函数会返回symbol
类型的值,该类型具有静态属性和静态方法。
每个从Symbol()
返回的symbol
值都是唯一的。一个symbol
值能作为对象属性的标识符;这是该数据类型仅有的目的。
```
const symbol1 = Symbol();
const symbol2 = Symbol(42);
const symbol3 = Symbol('foo');
console.log(typeof symbol1); // "symbol"
console.log(symbol3.toString()); // "Symbol(foo)"
console.log(Symbol('foo') === Symbol('foo')); // false
```
- 迭代器(Iterator)/ 生成器(Generator)
迭代器(Iterator
)是一种迭代的机制,为各种不同的数据结构提供统一的访问机制。任何数据结构只要内部有Iterator
接口,就可以完成依次迭代操作。
一旦创建,迭代器对象可以通过重复调用next()
显式地迭代,从而获取该对象每一级的值,直到迭代完,返回{ value: undefined, done: true }
。
```
function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
for (let i = start; i < end; i += step) {
yield i;
}
}
var a = makeRangeIterator(1,10,2)
a.next() // {value: 1, done: false}
a.next() // {value: 3, done: false}
a.next() // {value: 5, done: false}
a.next() // {value: 7, done: false}
a.next() // {value: 9, done: false}
a.next() // {value: undefined, done: true}
```
- Set / WeakSet
Set
对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
```
const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]
```
`WeakSet` 结构与 `Set` 类似,但区别有以下两点:
* `WeakSet` 对象中只能存放对象引用,不能存放值,而 `Set` 对象都可以。
* `WeakSet` 对象中存储的对象值都是被弱引用的,如果没有其他的变量或属性引用这个对象值,则这个对象值会被当成垃圾回收掉。正因为这样,`WeakSet` 对象是无法被枚举的,没有办法拿到它包含的所有元素。
```
const ws = new WeakSet()
const obj = {}
const foo = {}
ws.add(window)
ws.add(obj)
ws.has(window) // true
ws.has(foo) // false, 对象 foo 并没有被添加进 ws 中
ws.delete(window) // 从集合中删除 window 对象
ws.has(window) // false, window 对象已经被删除了
ws.clear() // 清空整个 WeakSet 对象
```
- Map / WeakMap
Map
对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。甚至可以使用NaN
来作为键值。
```
const myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN); // "not a number"
const otherNaN = Number("foo");
myMap.get(otherNaN); // "not a number"
```
`WeakMap` 对象是一组键 / 值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。跟 `Map` 的区别与 `Set` 跟 `WeakSet` 的区别相似。
```
const o1 = {};
const o2 = function(){};
const o3 = window;
const wm1 = new WeakMap();
wm1.set(o1, 37);
wm1.has(o1); // true
wm1.delete(o1);
wm1.has(o1); // false
wm1.set(o2, "azerty");
wm1.get(o2); // "azerty"
wm1.has(o2); // true
const wm2 = new WeakMap();
wm2.set(o1, o2); // value可以是任意值,包括一个对象
wm2.get(o2); // undefined,wm2中没有o2这个键
wm2.has(o2); // false
wm2.set(o3, undefined);
wm2.get(o3); // undefined,值就是undefined
wm2.has(o3); // true (即使值是undefined)
wm2.set(wm1, wm2); // 键和值可以是任意对象,甚至另外一个WeakMap对象
const wm3 = new WeakMap();
wm3.set(o1, 37);
wm3.get(o1); // 37
wm3.clear();
wm3.get(o1); // undefined,wm3已被清空
```
- Proxy / Reflect
Proxy
对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。
Reflect
是一个内置的对象,它提供拦截JavaScript
操作的方法。这些方法与Proxy
的方法相同。Reflect
不是一个函数对象,因此它是不可构造的。
```
const observe = (data, callback) => {
return new Proxy(data, {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, value, proxy) {
callback(key, value);
target[key] = value;
return Reflect.set(target, key, value, proxy)
}
})
}
const FooBar = { open: false };
const FooBarObserver = observe(FooBar, (property, value) => {
property === 'open' && value
? console.log('FooBar is open!!!')
: console.log('keep waiting');
});
console.log(FooBarObserver.open) // false
FooBarObserver.open = true // FooBar is open!!!
FooBarObserver.open = false // keep waiting
```
- Regex对象的扩展
* u 修饰符:
为了处理码点大于 `\uFFFF` 的 `Unicode` 字符(也就是说,会正确处理四个字节的 `UTF-16` 编码);`\uD83D\uDC2A` 是一个字符,但是 `es5` 不支持四个字节的 `UTF-16`,会将其识别成两个字符;加了 `u` 修饰符之后,`es6` 会将其识别成一个字符。
```
// i 修饰符:不区分大小写
/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true
```
* y 修饰符:“粘连”(sticky)修饰符
`y` 修饰符的作用与 `g` 修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,`g` 修饰符只要剩余位置中存在匹配就可,而 `y` 修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
```
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null
```
* 查看RegExp构造函数的修饰符
```
new RegExp(/abc/ig, 'i').flags // "i"
```
- Array 对象的扩展
* `Array.from()`
用于将两类对象转为真正的数组:类似数组的对象(`array-like object`)和可遍历(`iterable`)的对象(包括 `ES6` 新增的数据结构 `Set` 和 `Map`)。
```
Array.from('foo') // ["f", "o", "o"]
// 扩展运算符(...)也可以将某些数据结构转为数组
[ ...document.querySelectorAll('div') ] // NodeList对象
Array.from({ length: 3 }) // [ undefined, undefined, undefined ]
Array.from([1, 2, 3], x => x + x) // [2, 4, 6]
```
* `Array.of()`:用于将一组值,转换为数组
```
Array.of() // []
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
// 这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。
Array() // []
Array(7) // [empty, empty, empty, empty, empty, empty]
Array(3, 11, 8) // [3, 11, 8]
```
* 数组实例的 `copyWithin()`
在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组,会修改当前数组。
`Array.prototype.copyWithin(target, start = 0, end = this.length)`
它接受三个参数。这三个参数都应该是数值,如果不是,会自动转为数值。
1. target(必需):从该位置开始替换数据。
2. start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
3. end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
```
['a', 'b', 'c', 'd', 'e'].copyWithin(0, 3, 4) // ["d", "b", "c", "d", "e"]
[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, -2, -1) // [4, 2, 3, 4, 5]
```
* 数组实例的 `find() 和 findIndex()`
* 数组实例的 `fill()`:`fill` 方法使用给定值,填充一个数组
```
['a', 'b', 'c'].fill(7) // [7, 7, 7]
new Array(3).fill(7) // [7, 7, 7]
// 可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
[1, 2, 3, 4].fill(5, 1) // [1, 5, 5, 5]
```
* 数组实例的 `entries(),keys() 和 values()`
```
/*
* 用于遍历数组,都返回一个遍历器对象,可以用 for...of 循环进行遍历
* 唯一的区别是 keys() 是对键名的遍历、values() 是对键值的遍历、entries() 是对键值对的遍历
*/
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
```
* 数组的空位:明确将空位转为 `undefined`
ES7(ES2016)
-
数组实例的
includes()
返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes
方法类似[1, 2, 3].includes(2); // true [1, 2, 3].includes(4); // false [1, 2, NaN].includes(NaN); // true
该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
[1, 2, 3].includes(3, 3); // false [1, 2, 3].includes(3, -1); // true
另外,
Map
和Set
数据结构有一个has
方法,需要注意与includes
区分。-
Map
结构的has方法,是用来查找键名的,比如Map.prototype.has(key)、WeakMap.prototype.has(key)、Reflect.has(target, propertyKey)
。 -
Set
结构的has
方法,是用来查找值的,比如Set.prototype.has(value)、WeakSet.prototype.has(value)
。
-
-
幂运算符
**
console.log(2**10) // 1024 console.log(Math.pow(2, 10)) // 1024
-
模板字符串(Template string)
自ES7
起,带标签的模版字面量遵守以下转义序列的规则:-
Unicode
字符以"\u"
开头,例如\u00A9
-
Unicode
码位用"\u{}"表示,例如\u{2F804}
- 十六进制以
"\x"
开头,例如\xA9
- 八进制以
""
和数字开头,例如\251
-
ES8(ES2017)
-
async / await
Promise 的语法糖,专门解决回调地狱,async 函数返回一个 Promise 对象。async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数。async function f() { return 'hello world'; } f().then(v => console.log(v)) // "hello world" // 同时触发写法 let [foo, bar] = await Promise.all([getFoo(), getBar()]);
-
Object.values():返回一个给定对象自身的所有可枚举属性值的数组
const object1 = { a: 'somestring', b: 42, c: false } console.log(Object.values(object1)) // ["somestring", 42, false]
-
Object.entries():返回一个给定对象自身可枚举属性的键值对数组
const object1 = { a: 'somestring', b: 42 } console.log(Object.entries(object1)) // [["a","somestring"],["b",42]] for (let [key, value] of Object.entries(object1)) { console.log(`${key}: ${value}`) } // "a: somestring" // "b: 42"
-
padStart():用另一个字符串填充当前字符串(重复,如果需要的话),以便产生的字符串达到给定的长度。填充从当前字符串的开始(左侧)应用的。
const str1 = '5' console.log(str1.padStart(4, '0')) // "0005" // 若无第二个参数,用空格填充 console.log(str1.padStart(4)) // " 5"
-
padEnd():用一个字符串填充当前字符串(如果需要的话则重复填充),返回填充后达到指定长度的字符串。从当前字符串的末尾(右侧)开始填充。
const str1 = 'Breaded Mushrooms' console.log(str1.padEnd(25, '.')) // "Breaded Mushrooms........" const str2 = '200' console.log(str2.padEnd(5)) // "200 "
函数参数结尾逗号
-
SharedArrayBuffer对象
SharedArrayBuffer
对象用来表示一个通用的,固定长度的原始二进制数据缓冲区,类似于ArrayBuffer
对象,它们都可以用来在共享内存(shared memory
)上创建视图。与ArrayBuffer
不同的是,SharedArrayBuffer
不能被分离。// 参数length指所创建的数组缓冲区的大小,以字节(byte)为单位 let sab = new SharedArrayBuffer(1024) // 创建一个1024字节的缓冲
-
Atomics对象
Atomics对象
提供了一组静态方法用来对SharedArrayBuffer
对象进行原子操作。-
Atomics.add()
:将指定位置上的数组元素与给定的值相加,并返回相加前该元素的值。 -
Atomics.and()
:将指定位置上的数组元素与给定的值相与,并返回与操作前该元素的值。 -
Atomics.compareExchange()
:如果数组中指定的元素与给定的值相等,则将其更新为新的值,并返回该元素原先的值。 -
Atomics.exchange()
:将数组中指定的元素更新为给定的值,并返回该元素更新前的值。 -
Atomics.load()
:返回数组中指定元素的值。 -
Atomics.or()
:将指定位置上的数组元素与给定的值相或,并返回或操作前该元素的值。 -
Atomics.store()
:将数组中指定的元素设置为给定的值,并返回该值。 -
Atomics.sub()
:将指定位置上的数组元素与给定的值相减,并返回相减前该元素的值。 -
Atomics.xor()
:将指定位置上的数组元素与给定的值相异或,并返回异或操作前该元素的值。 -
Atomics.wait()
:检测数组中某个指定位置上的值是否仍然是给定值,是则保持挂起直到被唤醒或超时。返回值为 “ok”、“not-equal” 或 “time-out”。调用时,如果当前线程不允许阻塞,则会抛出异常(大多数浏览器都不允许在主线程中调用 wait())。 -
Atomics.wake()
:唤醒等待队列中正在数组指定位置的元素上等待的线程。返回值为成功唤醒的线程数量。 -
Atomics.isLockFree(size)
:可以用来检测当前系统是否支持硬件级的原子操作。对于指定大小的数组,如果当前系统支持硬件级的原子操作,则返回 true;否则就意味着对于该数组,Atomics 对象中的各原子操作都只能用锁来实现。此函数面向的是技术专家。
-
-
Object.getOwnPropertyDescriptors():用来获取一个对象的所有自身属性的描述符
const obj = { foo: 123, get bar() { return 'abc' } }; Object.getOwnPropertyDescriptors(obj) // { foo: // { value: 123, // writable: true, // enumerable: true, // configurable: true }, // bar: // { get: [Function: bar], // set: undefined, // enumerable: true, // configurable: true } }
-
浅拷贝一个对象
Object.assign()
方法只能拷贝源对象的可枚举的自身属性,同时拷贝时无法拷贝属性的特性们,而且访问器属性会被转换成数据属性,也无法拷贝源对象的原型,该方法配合Object.create()
方法可以实现上面说的这些。Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) );
-
创建子类
创建子类的典型方法是定义子类,将其原型设置为超类的实例,然后在该实例上定义属性。这么写很不优雅,特别是对于 getters 和 setter 而言。 相反,您可以使用此代码设置原型:function superclass() {} superclass.prototype = { // 在这里定义方法和属性 }; function subclass() {} subclass.prototype = Object.create(superclass.prototype, Object.getOwnPropertyDescriptors({ // 在这里定义方法和属性 }));
-
ES9(ES2018)
-
for await…of
for await...of
语句创建一个循环,该循环遍历异步可迭代对象以及同步可迭代对象,包括: 内置的String
,Array
,类似数组对象 (例如arguments
或NodeList
),TypedArray
,Map
,Set
和用户定义的异步/同步迭代器。其会调用自定义迭代钩子,并为每个不同属性的值执行语句。async function* asyncGenerator() { var i = 0 while (i < 3) { yield i++ } } (async function() { for await (num of asyncGenerator()) { console.log(num) } })() // 0 // 1 // 2
模板字符串(Template string)
ES9
开始,模板字符串允许嵌套支持常见转义序列,移除对ECMAScript
在带标签的模版字符串中转义序列的语法限制。-
正则表达式 Unicode 转义
正则表达式中的Unicode
转义符允许根据Unicode
字符属性匹配Unicode
字符。 它允许区分字符类型,例如大写和小写字母,数学符号和标点符号。// 匹配所有数字 const regex = /^\p{Number}+$/u; regex.test('²³¹¼½¾') // true regex.test('㉛㉜㉝') // true regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true // 匹配所有空格 \p{White_Space} // 匹配各种文字的所有字母,等同于 Unicode 版的 \w [\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}] // 匹配各种文字的所有非字母的字符,等同于 Unicode 版的 \W [^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}] // 匹配 Emoji /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu // 匹配所有的箭头字符 const regexArrows = /^\p{Block=Arrows}+$/u; regexArrows.test('←↑→↓⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇧⇩') // true
-
正则表达式 s/dotAll 模式
JS
正则增加了一个新的标志s
用来表示dotAll
,这可以匹配任意字符。const re = /foo.bar/s; // 等价于 const re = new RegExp('foo.bar', 's'); re.test('foo\nbar'); // true re.dotAll; // true re.flags; // "s"
具名组匹配
const RE_DATE = /(?\d{4})-(?\d{2})-(?\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // 1999
const month = matchObj.groups.month; // 12
const day = matchObj.groups.day; // 31
对象扩展操作符
Promise.prototype.finally()
finally()
方法会返回一个Promise
,当promise
的状态变更,不管是变成rejected
或者fulfilled
,最终都会执行finally()
的回调。
fetch(url)
.then((res) => {
console.log(res)
})
.catch((error) => {
console.log(error)
})
.finally(() => {
console.log('结束')
})
ES10(ES2019)
- 数组实例的
flat()
用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。参数depth
表示要提取嵌套数组的结构深度,默认值为 1。
console.log([1 ,[2, 3]].flat()); // [1, 2, 3]
// 指定转换的嵌套层数
console.log([1, [2, [3, [4, 5]]]].flat(2)); // [1, 2, 3, [4, 5]]
// 不管嵌套多少层【使用 Infinity 作为深度,展开任意深度的嵌套数组】
console.log([1, [2, [3, [4, 5]]]].flat(Infinity)); // [1, 2, 3, 4, 5]
// 自动跳过空位【会移除数组中的空项】
console.log([1, [2, , 3]].flat()); // [1, 2, 3]
// 传入 <=0 的整数将返回原数组,不“拉平”
console.log([1, [2, [3, [4, 5]]]].flat(0)); // [1, [2, [3, [4, 5]]]]
console.log([1, [2, [3, [4, 5]]]].flat(-10)); // [1, [2, [3, [4, 5]]]]
- 数组实例的
flatMap()
首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与map
和连着深度值为1的flat
几乎相同,但flatMap
通常在合并成一种方法的效率稍微高一些。
[1, 2, 3, 4].flatMap(x => x * 2); // [2, 4, 6, 8]
[1, 2, 3, 4].flatMap(x => [x * 2]); // [2, 4, 6, 8]
[1, 2, 3, 4].flatMap(x => [[x * 2]]); // [[2], [4], [6], [8]]
[1, 2, 3, 4].map(x => [x * 2]); // [[2], [4], [6], [8]]
字符串实例的
trimStart() / trimLeft() / trimEnd() / trimRight()
去除字符首或尾的空格,trimStart()
跟trimEnd()
才是标准方法,trimLeft()
跟trimRight()
只是别名Object.fromEntries()
把键值对列表转换为一个对象,它是Object.entries()
的反函数。
const entries = new Map([
['foo', 'bar'],
['baz', 42]
])
console.log(Object.fromEntries(entries)) // Object { foo: "bar", baz: 42 }
-
Symbol.prototype.description
通过工厂函数Symbol()
创建符号时,您可以选择通过参数提供字符串作为描述:
Symbol('desc').toString(); // "Symbol(desc)"
Symbol('desc').description; // "desc"
Symbol('').description; // ""
Symbol().description; // undefined
//全局 symbols
Symbol.for('foo').toString(); // "Symbol(foo)"
Symbol.for('foo').description; // "foo"
Function.prototype.toString()
现在返回精确字符,包括空格和注释try-catch
catch
的参数可省略
ES11(ES2020)
-
String.prototype.matchAll
返回一个包含所有匹配正则表达式及分组捕获结果的迭代器。
var regexp = /t(e)(st(\d?))/g
var str = 'test1test2'
str.match(regexp) // ['test1', 'test2']
str.matchAll(regexp) // RegExpStringIterator {}
[...str.matchAll(regexp)] // [ ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', length: 4], ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', length: 4] ]
- 动态
import()
const modelpath = '/demo'
import(`@/pages${modelpath}`).then(module => {}).catch(err => {})
import.meta
import.meta
会返回一个对象,有一个url
属性,返回当前模块的url
路径,只能在模块内部使用。export * as XX from 'module'
和import * as XX from 'module'
Promise.allSettled()
Promise.allSettled
方法返回一个在所有给定的promise
都已经fulfilled
或rejected
后的promise
,并带有一个对象数组,每个对象表示对应的promise
结果。BigInt
现在的基本数据类型(值类型)不止5种(ES6之后是六种)了哦!加上BigInt
一共有七种基本数据类型,分别是:String、Number、Boolean、Null、Undefined、Symbol、BigInt
BigInt
可以表示任意大的整数。可以用在一个整数字面量后面加n
的方式定义一个BigInt
,如:10n,或者调用函数BigInt()
。globalThis
指向全局对象,浏览器下指向window
可选链操作符(?.)
info.animal?.reptile?.tortoise
空值合并操作符(??)
当左侧的操作数为null
或者undefined
时,返回其右侧操作数,否则返回左侧操作数。
与逻辑或操作符(||
)不同,逻辑或操作符会在左侧操作数为假值时返回右侧操作数。
const foo = null ?? 'default string';
console.log(foo); // "default string"
const baz = 0 ?? 42;
console.log(baz); // 0
ES12(ES2021)(预计将在2021年年中发布)
-
String.prototype.replaceAll
replaceAll
返回一个全新的字符串,所有符合匹配规则的字符都将被替换掉,替换规则可以是字符串或者正则表达式。
let string = 'I like 前端,I like 前端公虾米'
console.log(string.replace(/like/g,'love')) // 'I love 前端,I love 前端公虾米'
console.log(string.replaceAll('like','love')) // 'I love 前端,I love 前端公虾米'
需要注意的是,
replaceAll
在使用正则表达式的时候,如果非全局匹配(/g
),则replaceAll()
会抛出一个异常
console.log(string.replaceAll(/like/,'love')) // TypeError
Promise.any
当Promise
列表中的任意一个promise
成功resolve
则返回第一个resolve
的结果状态,如果所有的promise
均reject
,则抛出异常表示所有请求失败。
Promise.race
一旦某个promise
触发了resolve
或者reject
,就直接返回了该状态结果,并不在乎其成功或者失败。WeakRefs
当我们通过(const、let、var
)创建一个变量时,垃圾收集器GC
将永远不会从内存中删除该变量,只要它的引用仍然存在可访问。WeakRef
对象包含对对象的弱引用。对对象的弱引用是不会阻止垃圾收集器GC
恢复该对象的引用,则GC
可以在任何时候删除它。
WeakRefs
在很多情况下都很有用,比如使用Map
对象来实现具有很多需要大量内存的键值缓存,在这种情况下最方便的就是尽快释放键值对占用的内存。
目前,可以通过WeakMap()
或者WeakSet()
来使用WeakRefs
。逻辑运算符和赋值表达式
表达式a op= b
等同于a = a op (a = b)
a ||= b
//等价于
a = a || (a = b) // 当LHS值不存在时,将RHS变量赋值给LHS
a &&= b
//等价于
a = a && (a = b) // 当LHS值存在时,将RHS变量赋值给LHS
a ??= b
//等价于
a = a ?? (a = b) // 当LHS值为null或者undefined时,将RHS变量赋值给LHS
- 数字分隔符号
数字分隔符,可以在数字之间创建可视化分隔符,通过_
下划线来分割数字,使数字更具可读性
const money = 1_000_000_000
//等价于
const money = 1000000000
const totalFee = 1000.12_34
//等价于
const totalFee = 1000.1234
// 该新特性同样支持在八进制数中使用
const number = 0o123_456
//等价于
const number = 0o123456