|
参考文献: https://tuobaye.com/2018/11/27/%E7%BB%86%E8%A7%A3JavaScript-ES7-ES8-ES9-%E6%96%B0%E7%89%B9%E6%80%A7/
http://www.imooc.com/article/291875
https://hijiangtao.github.io/2019/07/05/Diff-ECMAScript-2019/
ES7
1. Array.prototype.includes()方法
['a', 'b', 'c', 'd'].includes('b') // true
['a', 'b', 'c', 'd'].includes('b', 1) // true
['a', 'b', 'c', 'd'].includes('b', 2) // false
var ary1 = [NaN];
console.log(ary1.indexOf(NaN))//-1
console.log(ary1.includes(NaN))//true
2. 求幂运算符(**)
用**来替代Math.pow。
等价于
ES8
1. Async Functions
Async Functions也就是我们常说的Async/Await。Async/Await是一种用于处理JS异步操作的语法糖,可以帮助我们摆脱回调地狱,编写更加优雅的代码。
通俗的理解,async关键字的作用是告诉编译器对于标定的函数要区别对待。当编译器遇到标定的函数中的await关键字时,要暂时停止运行,带到await标定的函数处理完毕后,再进行相应操作。如果该函数fulfilled了,则返回值是resolve value,否则得到的就是reject value。
拿普通的promise写法来对比:
async function asyncFunc() {
const result = await otherAsyncFunc();
console.log(result);
}
// Equivalent to:
function asyncFunc() {
return otherAsyncFunc()
.then(result => {
console.log(result);
});
}
并行处理多个函数:
async function asyncFunc() {
const [result1, result2] = await Promise.all([
otherAsyncFunc1(),
otherAsyncFunc2(),
]);
console.log(result1, result2);
}
// Equivalent to:
function asyncFunc() {
return Promise.all([
otherAsyncFunc1(),
otherAsyncFunc2(),
])
.then([result1, result2] => {
console.log(result1, result2);
});
}
处理错误:
async function asyncFunc() {
try {
await otherAsyncFunc();
} catch (err) {
console.error(err);
}
}
// Equivalent to:
function asyncFunc() {
return otherAsyncFunc()
.catch(err => {
console.error(err);
});
}
2. SharedArrayBuffer和Atomics
SharedArrayBuffer允许在多个 workers 和主线程之间共享 SharedArrayBuffer 对象的字节。这种共享有两个好处:
- 可以更快地在 workers 之间共享数据。
- workers 之间的协调变得更简单和更快(与 postMessage() 相比)
API:
构造函数: new SharedArrayBuffer(length)
静态属性: SharedArrayBuffer[Symbol.species]
实例属性: SharedArrayBuffer.prototype.byteLength()
SharedArrayBuffer.prototype.slice(start, end)
Atomics 方法可以用来与其他 workers 进行同步。以下两个操作可以让你读取和写入数据,并且不会被编译器重新排列:
- Atomics.load(ta : TypedArray, index)
- Atomics.store(ta : TypedArray, index, value : T)
这个想法是使用常规操作读取和写入大多数数据,而 Atomics 操作(load ,store 和其他操作)可确保读取和写入安全。通常,要使用自定义同步机制(例如)可以基于Atomics实现。
API:
Atomic 函数的主要操作数必须是 Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array 或 Uint32Array 的一个实例。它必须包裹一个 SharedArrayBuffer.
- Atomics.load(ta : TypedArray, index) : T
读取和返回 ta[index] 上的元素,返回数组指定位置上的值。
- Atomics.store(ta : TypedArray, index, value : T) : T
在 ta[index] 上写入 value,并且返回 value。
- Atomics.exchange(ta : TypedArray, index, value : T) : T
将 ta[index] 上的元素设置为 value ,并且返回索引 index 原先的值。
- Atomics.compareExchange(ta : TypedArray, index, expectedValue, replacementValue) : T
如果 ta[index] 上的当前元素为 expectedValue , 那么使用 replacementValue 替换。并且返回索引 index 原先(或者未改变)的值。
- Atomics.add(ta : TypedArray, index, value) : T
执行 ta[index] += value 并返回 ta[index] 的原始值。
- Atomics.sub(ta : TypedArray, index, value) : T
执行 ta[index] -= value 并返回 ta[index] 的原始值。
- Atomics.and(ta : TypedArray, index, value) : T
执行 ta[index] &= value 并返回 ta[index] 的原始值。
- Atomics.or(ta : TypedArray, index, value) : T
执行 ta[index] |= value 并返回 ta[index] 的原始值。
- Atomics.xor(ta : TypedArray, index, value) : T
执行 ta[index] ^= value 并返回 ta[index] 的原始值。
- Atomics.wait(ta: Int32Array, index, value, timeout=Number.POSITIVE_INFINITY) : (‘not-equal’ | ‘ok’ | ‘timed-out’)
如果 ta[index] 的当前值不是 value ,则返回 ‘not-equal’。否则(等于value时)继续等待,直到我们通过 Atomics.wake() 唤醒或直到等待超时。 在前一种情况下,返回 ‘ok’。在后一种情况下,返回’timed-out’。timeout 以毫秒为单位。记住此函数执行的操作:“如果 ta[index] 为 value,那么继续等待” 。
- Atomics.wake(ta : Int32Array, index, count)
唤醒等待在 ta[index] 上的 count workers。
3. Object.values and Object.entries
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.values(obj); // ['yyy', 'zzz', 'xxx']
Object.values('es8'); // ['e', 's', '8']
const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]
const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10': 'xxx']]
Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]
4. String padding
为 String 对象增加了 2 个函数:padStart 和 padEnd。填补字符串的首部和尾部,为了使得到的结果字符串的长度能达到给定的长度(targetLength)。你可以通过特定的字符,或者字符串,或者默认的空格填充它。
str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])
'es8'.padStart(2); // 'es8'
'es8'.padStart(5); // ' es8'
'es8'.padStart(6, 'woof'); // 'wooes8'
'es8'.padStart(14, 'wow'); // 'wowwowwowwoes8'
'es8'.padStart(7, '0'); // '0000es8'
'es8'.padEnd(2); // 'es8'
'es8'.padEnd(5); // 'es8 '
'es8'.padEnd(6, 'woof'); // 'es8woo'
'es8'.padEnd(14, 'wow'); // 'es8wowwowwowwo'
'es8'.padEnd(7, '6'); // 'es86666'
5. Object.getOwnPropertyDescriptors
const obj = {
get es7() { return 777; },
get es8() { return 888; }
};
Object.getOwnPropertyDescriptor(obj);
// {
// es7: {
// configurable: true,
// enumerable: true,
// get: function es7(){}, //the getter function
// set: undefined
// },
// es8: {
// configurable: true,
// enumerable: true,
// get: function es8(){}, //the getter function
// set: undefined
// }
// }
6. 结尾逗号
// 参数定义时
function foo(
param1,
param2,
) {}
// 函数调用时
foo(
'abc',
'def',
);
// 对象中
let obj = {
first: 'Jane',
last: 'Doe',
};
// 数组中
let arr = [
'red',
'green',
'blue',
];
ES9新特性
1.异步迭代器:异步迭代器对象的next()方法返回了一个Promise,解析后的值跟普通的迭代器类似。
async function example() {
// 普通迭代器:
const iterator = createNumberIterator();
iterator.next(); // Object {value: 1, done: false}
iterator.next(); // Object {value: 2, done: false}
iterator.next(); // Object {value: 3, done: false}
iterator.next(); // Object {value: undefined, done: true}
// 异步迭代器:
const asyncIterator = createAsyncNumberIterator();
const p = asyncIterator.next(); // Promise
await p;// Object {value: 1, done: false}
await asyncIterator.next(); // Object {value: 2, done: false}
await asyncIterator.next(); // Object {value: 3, done: false}
await asyncIterator.next(); // Object {value: undefined, done: true}
}
2. Rest/Spread 属性
rest参数和展开运算符,这项特性在ES6中已经引入,但是ES6中仅限于数组。在ES9中,为对象提供了像数组一样的rest参数和扩展运算符。
const obj = {
a: 1,
b: 2,
c: 3
}
const { a, ...param } = obj;
console.log(a) //1
console.log(param) //{b: 2, c: 3}
function foo({a, ...param}) {
console.log(a); //1
console.log(param) //{b: 2, c: 3}
}
3. Promise.prototype.finally()
finally的回调总会被执行。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
4. 命名捕获组
ES9中可以通过名称来识别捕获组:
before:
const RE_DATE = /([0-9]{4})-([0-9]{2})-([0-9]{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31
after:
const RE_DATE = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<date>[0-9]{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.date; // 31
// 使用解构语法更为简便
const {groups: {day, year}} = RE_DATE.exec('1999-12-31');
console.log(year); // 1999
console.log(day); // 31
ES10新特性
1. 选择性的catch绑定
在使用try catch错误异常处理时,可以选择性的给catch传入参数(可以不给catch传参)
正常使用try catch:
try {
// do something
} catch (err) {
// console.log('err', err);
}
在es10中使用时,可以:
try {
// do something
} catch {
// do something
}
2. JSON.superset
背景: JSON内容可以正常包含 行分隔符(\u2028)和 段落分隔符(\u2029)而ECMAScript却不行。
在ES10中,可以直接使用
而不会在提示错误。
3. Symbol.prototype.description
为Symbol类型增加Symbol.prototype.description的一个访问器属性,用来获取Symbol类型数据的描述信息。
console.log(Symbol('test').description);
// 'test'
console.log(Symbol.for('test').description);
// 'test'
console.log(Symbol.iterator.description);
// 'Symbol.iterator'
4. Function.prototype.toString
在ES10之后,函数调用toString()方法,将准确返回原有信息,包括空格和注释等。
let funcToString = function () {
//do something
console.log('test');
}
/**
"function () {
//do something
console.log('test');
}"
*/
5. Object.fromEntries()
Object.fromEntries()是Object.entries()的反转。
const obj = { foo: 'bar', baz: 42}
let res1 = Object.entries(obj);
console.log(res1);
// [['foo', 'bar'], ['baz', 42]]
let obj1= Object.fromEntries(res1);
console.log(obj1);
// {foo: 'bar', baz: 42}
map转换为object
let map = new Map([['name','alex'], ['age', 18]]);
const obj2 = Object.fromEntries(map);
console.log(obj2);
// object {name: 'alex', age: 18}
6. 更友好的JSON.stringify
正常字符的表示不变:
JSON.stringify('𝌆')
// → '"𝌆"'
JSON.stringify('\uD834\uDF06')
// → '"𝌆"'
而无法用 UTF-8 编码表示的字符会被序列化为转移序列:
JSON.stringify('\uDF06\uD834')
// → '"\\udf06\\ud834"'
JSON.stringify('\uDEAD')
// → '"\\udead"'
7. String.prototype.{trimStart, trimEnd}
trimStart()从字符串开头删除空格,返回一个新的字符串,不会修改原字符串。
let str = ' hello, miss cecelia!';
console.log(str.trimStart());
// 'hello, miss cecelia!'
trimEnd()从字符串右端开始移除空白字符,返回一个新的字符串,不会修改原字符串。
let str = ' hello, miss cecelia! ';
console.log(str.trimEnd());
// ' hello, miss cecelia!'
8. Array.prototype.{flat, flatMap}
Array.prototype.flat()可显式地传入参数,表示打平的层级。不传参数,表示只打平第一级。
let arr = [1,2,3,[1,2,[3,[4]]]];
console.log(arr.flat());
// [1,2,3,1,2,[3,[4]]]
console.log(arr.flat(2));
// [1,2,3,1,2,3,[4]]
flatMap()方法:可以看作flat和map组合在一起的结果:
['My dog', 'is awesome'].map(words => words.split(' '))
// [ [ 'My', 'dog' ], [ 'is', 'awesome' ] ]
['My dog', 'is awesome'].flatMap(words => words.split(' '))
//[ 'My', 'dog', 'is', 'awesome' ]
ES 12 新特性
1. String.propotype.replaceAll
看到replaceAll这个词,相比很容易联想到replace。在JavaScript中,replace方法只能是替换字符串中匹配到的第一个实例字符,而不能进行全局多项匹配替换,唯一的办法是通过正则表达式进行相关规则匹配替换。
let string = ' I like apple. And I also like peach.'
// 使用replace替换一次
let replaceStr = string.replace('like', 'dislike');
console.log(replaceStr); // I dislike apple. And I also like peach.
// 使用replace替换全部
let replaceStr2 = string.replace(/like/g, 'dislike');
console.log(replaceStr2); // I dislike apple. And I also dislike peach.
// 使用replaceAll 替换全部
let replaceStr3 = string.replaceAll('like', 'dislike');
console.log(replaceStr3); // I dislike apple. And I also dislike peach.
// 使用replaceAll + 正则全局(g)替换全部
let replaceStr4 = string.replaceAll(/like/g, 'dislike'); console.log(replaceStr4);
// 注意,在replaceAll 中使用正则表达式,必须要加/g, 否则会报错TypeError
2. Promise.any()
当Promise数组中至少有一个返回了resolved Promise,就返回第一resolved Promise. 如果全部是rejected Promise, 则返回一个rejected Promise.(与Promise race比较,要等到第一resolved才返回结果,而不是第一有结果的Promise就返回)
Promise.any([
new Promise((resolve, reject) => setTimeout(reject, 500, 'jujue1')),
new Promise((resolve, reject) => setTimeout(resolve, 1000, 'jieshou2')),
new Promise((resolve, reject) => setTimeout(resolve, 1200, 'jieshou3')),
]).then(value => console.log('输出结果:', value))
.catch(err => console.log(err)) // 输出结果: jieshou2
Promise.any([
new Promise((resolve, reject) => setTimeout(reject, 500, 'jujue1')),
new Promise((resolve, reject) => setTimeout(reject, 1000, 'jieshou2')),
new Promise((resolve, reject) => setTimeout(reject, 200, 'jieshou3')),
]).then(value => console.log('输出结果:', value)).catch(err => console.log('全部reject',err)) // 全部reject AggregateError: All promises were rejected
对比Promise.race()
Promise.race([
new Promise((resolve, reject) => setTimeout(reject, 500, 'jujue1')),
new Promise((resolve, reject) => setTimeout(resolve, 1000, 'jieshou2')),
new Promise((resolve, reject) => setTimeout(resolve, 1200, 'jieshou3')),
]).then(value => console.log('输出结果:', value)).catch(err => console.log('reject结果',err)) // reject结果 jujue1
Promise.race([
new Promise((resolve, reject) => setTimeout(reject, 500, 'jujue1')),
new Promise((resolve, reject) => setTimeout(reject, 1000, 'jieshou2')),
new Promise((resolve, reject) => setTimeout(reject, 200, 'jieshou3')),
]).then(value => console.log('输出结果:', value)).catch(err => console.log('reject结果',err)) //reject结果 jieshou3
3. WeakRef: 使用WeakRef的class类创建对对象的弱引用(当不存在对对象的其他引用时,不会阻止GC的回收行为)。具体的函数WeakSet() , WeakMap()
WeakRef用在何处? 如使用map实现许多个需要大量内存的键值缓存,在这种情况下最方便的就是尽快释放键值对占用的内存。
例如: 使用方法追踪特定对象调用某个方法的次数,超过1000次提示.
let map = new Map();
function doSomething() {
...
}
function count(obj) {
doSomething(obj);
let num = map.get(obj) || 0;
num++;
if ( num > 1000) {
console.log('当前对象调用次数超过1000次');
}
map.set(obj, num)
}
上述代码使用map, 虽然能够实现既定的功能,但是有可能会存在内容溢出(每个调用count的对象都会被永久保存在map中,这份引用一直存在,不会被GC回收)。
我们可以使用WeakMap
let wmap = new WeakMap();
function doSomething() {
...
}
function count(obj) {
doSomething();
let num = wmap.get(obj) || 0;
num ++ ;
if ( num > 1000) {
console.log('当前对象调用次数超过1000次');
}
wmap.set(obj, num);
}
使用WeakMap的优势: 弱引用,如果没有其他引用,那么就可以被GC回收。
注意:WeakSet和WeakMap都是不可迭代的。
4. 逻辑运算符和赋值表达式
a ||= b
// 等价于
a = a || (a = b);
a &&= b
// 等价于
a = a && (a = b);
a ??= b
// 等价于
a = a ?? (a = b);
小结:
来源:https://www.cnblogs.com/ceceliahappycoding/p/11354353.html |