ES2015到ES2021总结
ES2021
逻辑赋值运算符
逻辑赋值运算符结合逻辑运算符和赋值运算符,它让代码变得简短、让变量和对象属性条件赋值变得简单。ES2021将推出三个新的逻辑操作符,每一个操作符都有两个运算元。
||= // combines logical OR with ASSIGN
&&= // combines logical AND with ASSIGN
??= // combines NULLISH with ASSIGN
逻辑OR||=操作符是结合了逻辑||操作符和赋值操作符。当前面的值是假值的时候将右边运算元赋值给左边运算元,相当于形式a || (a = b)。
let thirdPlace = 5;
let secondPlace = false;
let firstPlace = null;
thirdPlace ||= 3;
secondPlace ||= 2;
firstPlace ||= 1;
console.log(thirdPlace); // "5"
console.log(secondPlace); // "2"
console.log(firstPlace); // "1"
同样的,逻辑AND赋值运算符&&=结合逻辑&&操作符和赋值操作符,当且仅当运算符左侧的值是真值的时候将运算元右侧的值赋值给运算元左侧,相当于a && (a = b)的简写形式。
let thirdPlace = 5;
let secondPlace = false;
let firstPlace = null;
thirdPlace &&= 3;
secondPlace &&= 2;
firstPlace &&= 1;
console.log(thirdPlace); // "3"
console.log(secondPlace); // "false"
console.log(firstPlace); // "null"
空值赋值操作符??=是a??(a=b)的简写形式。当且仅当前面一个值是null或者undefined的时候将第二个运算元赋值给第一个运算元。
let thirdPlace = 5;
let secondPlace = false;
let firstPlace = null;
thirdPlace ??= 3;
secondPlace ??= 2;
firstPlace ??= 1;
console.log(thirdPlace); // "5"
console.log(secondPlace); // "false"
console.log(firstPlace); // "1"
当初始化对象属性的时候,这些新操作符非常好用。这些操作符帮助我们保证在person对象内部的firstName属性在没有赋值的时候已经初始化了Commander值。
以前的精简形式:
(() => {
const person = {
firstName: 'Unnamed'
}
person.firstName || (person.firstName = 'Commander');
console.log(person.firstName); // "Unnamed"
person.lastName || (person.lastName = 'Shepard');
console.log(person.lastName); // "Shepard"
})();
ES2021整个结构更加精简:
(() => {
const person = {
firstName: 'Unnamed'
}
person.firstName ||= 'Commander';
console.log(person.firstName); // "Unnamed"
person.lastName ||= 'Shepard';
console.log(person.lastName); // "Shepard"
})();
总结来说,你只是简化了赋值默认值而不是初始化变量。 从:
person.firstName = person.firstName|| person.firstName='Commander';
到:
person.firstName ||= 'Commander';
注意:除此之外,采用老的方式实现这种形式,将阻断可能存在的getter方法。另一种方式是如果存在__getter的话就调用__getter。
字符串替换
当替换一个字符串中所有存在的子序列时,最好的方式是使用正则表达式。你也可以使用polyfill的函数replaceAllPolyfill(),这个方法对字符串产生一个各自的具体的正则表达式全局搜索。
const winnersPhrase = 'This 111 is the 111 text 111 to gratulate 111 the winners 111 of the 111 race!';
const replaceAllPolyfill = (string, find, replace) => {
return string.replace(new RegExp(find, 'g'),
replace);
}
const correctPhrase = replaceAllPolyfill(winnersPhrase, ' 111', '');
console.log(correctPhrase); // This is the text to gratulate the winners of the race!
另外一种实现形式是采用字符串方法split(),这个方法以参入的子序列为节点分割字符串为数组,然后再针对这个数组调用call()方法,声明新的插入字符串,将所有的子序列合在一起。
const winnersPhrase = 'This 111 is the 111 text 111 to gratulate 111 the winners 111 of the 111 race!';
const replaceAllPolyfill = (string, find, replace) => {
return string.replace(new RegExp(find, 'g'),
replace);
}
const correctPhrase = winnersPhrase.split(' 111'). join('');
console.log(correctPhrase); // This is the text to gratulate the winners of the race!
出于性能原因这些方式都是低效的。对于长字符串,频繁的出现字符串搜索。replaceAll()方法在未来会简化这个流程,它将替换字符串中所有存在的与第一个参数相同的子序列为第二个参数的字符串序列。
const winnersPhrase = 'This 111 is the 111 text 111 to gratulate 111 the winners 111 of the 111 race!';
const correctPhrase = winnersPhrase.replaceAll(' 111', '');
console.log(correctPhrase); // This is the text to gratulate the winners of the race!
你可以看出来,我们可以优化一切以减少代码编写和更加高效。
Promises
ES2020已经通过了Promise的allSettled()方法。ES2021 Promise阵营将有一个新的成员,any()。它期望一个Iterable的prmoses,然后返回一个最快fulfilled状态的promise。当所有的promise都rejected了,any将返回一个rejected的promise。
(async () => {
const promisesToBeResolved = [
Promise.resolve(555),
Promise.resolve(666),
Promise.resolve(777),
];
try {
const firstResolver = await Promise.any(promisesToBeResolved);
console.log(firstResolver); // --> 555
} catch (error) {
console.error(error);
}
})();
(async () => {
const promisesSomeToBeRejected = [
Promise.reject(555),
Promise.reject(666),
Promise.resolve(777),
];
try {
const firstResolver = await Promise.any(promisesSomeToBeRejected);
console.log(firstResolver); // --> 777
} catch (error) {
console.error(error);
}
})();
(async () => {
const promisesAllToBeRejected = [
Promise.reject(1),
Promise.reject(2),
Promise.reject(5),
];
try {
const firstResolver = await Promise.any(promisesAllToBeRejected);
console.log(firstResolver);
} catch (error) {
console.error(error); // All promises were rejected
}
}
)();
可以看出这个例子,any()方法等待第一个resolved值,而且只会打印firstResolver,当所有的promise都rejected,它将在trycatch中抛出错误,第三个例子清楚的证明了为什么程序没有打印出firstResolver。
WeakRefs
我敢打赌你知道WeakSet和WeakMap,他们从ES2015开始被实现的。WeakSet是对象的集合,WeakMap是键值对的集合,而他的键必须是一个对象。他们之间的联系属于弱引用。也就是说这些对象作为垃圾回收的一部分,如果没有其他强引用,可以从内存中被移除。一个对象的弱引用是不会阻止垃圾回收器移除内存中的这个对象。相反,一个普通(强)引用的对象会保留这个对象在内存中。
ES2021将可以实现人为使用WeakRef对象而不用WeakSet和WeakMap来创建一个对象的若引用。这个符合需要的提案警告你在使用WeakRef时一定要小心。总之,使用之前一定有合理理由。根本上来说,我们应该尽可能的避免使用WeakRef。垃圾回收器已经够复杂和系统依赖的,所以这很难去预测垃圾回收器的具体行为。
二进制、十六进制和大数终可读
以前容易读懂/分辨大数吗?我看未必。同样的情况出现在长整形,二进制和十六进制数字。所以为什么要等到2021年才来介绍可读性强的大数字呢?我也不知道,但是其他语言(Java、Python、Perl、Ruby、C#)都表现的良好,闲杂也该JavaScript了吧。这个数字分隔符将唤醒我们的眼睛。
const goldstack1 = 785_00;
const gemstack = 1_000_000_000;
console.log(goldstack1); // 78500
console.log(gemstack); // 1000000000
console.log(goldstack1 === 78500); // true
console.log(gemstack === 1000000000); // true
我们通过在数字相符的组之间放置分隔符使数字值更加的可读,分隔符适用于十进制表示法的数字以及二进制或十六进制表示法的数字,以及ES2020中引入的BigInts。

注意:分隔符不会影响===操作符比较两个值
ES2015(ES6)
node 支持:node v6.17.1 以上支持 99%。
- ES6 的第一个版本;
- map, forEach, filter
map, forEach, filter
map
1 let nums = [1, 3, 5, 7, 9]; 2 console.log(nums); // [ 1, 3, 5, 7, 9 ] 3 4 // map方法传入一个函数,遍历数组中的每一个元素并将这个方法作用在元素上,最后返回一个新的数组,不改变原数组 5 let arr1 = nums.map(i => i + 1); 6 console.log(arr1); // [ 2, 4, 6, 8, 10 ] 7 // map操作返回新的数组,所以下面返回false 8 console.log(arr1 === nums); // false 9 10 // map中传入的函数可以有两个参数,e代表遍历过程中当前的元素,i表示当前元素的索引,索引从0开始 11 let arr2 = nums.map((e, i) => e + i); 12 console.log(arr2); // [ 1, 4, 7, 10, 13 ]
forEach
let nums = [2, 4, 6, 8, 10]; console.log(nums); // [ 2, 4, 6, 8, 10 ] // forEach方法传入一个函数,该函数作用于数组中的每一个元素 // forEach没有返回值,且不会修改原来的数组 let arr = nums.forEach(e => e + 1); console.log(arr); // undefined console.log(nums); // [ 2, 4, 6, 8, 10 ] // 依次分行打印2,4,6,8,10 nums.forEach(e => console.log(e)); // i: 0, e: 2 // i: 1, e: 4 // i: 2, e: 6 // i: 3, e: 8 // i: 4, e: 10 nums.forEach((e, i) => console.log('i: ' + i + ', e: ' + e));
filter
let nums = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(nums); // [ 1, 2, 3, 4, 5, 6, 7, 8 ]
// filter传入一个函数,通过遍历数组找出满足该函数的所有元素并返回一个新数组
let odds = nums.filter(e => e % 2 !== 0); // 过滤出所有奇数
console.log(odds); // [ 1, 3, 5, 7 ]
let evens = nums.filter(e => e % 2 === 0); // 过滤出所有偶数
console.log(evens); // [ 2, 4, 6, 8 ]
// i: 5, e: 6
// i: 6, e: 7
// i: 7, e: 8
let bigs = nums.filter((e, i) => {
if (e > 5) {
console.log('i: ' + i + ', e: ' + e);
}
});
Class 类
class Human { // 类的构造方法 constructor(name, age) { this.name = name; this.age = age; } // 类的成员方法 say() { console.log('hello, my name is ' + this.name + ', my age is ' + this.age); } static f() { console.log('hello, I am static method!'); } } class Teacher extends Human { constructor(name, age, major) { // 调用父类的构造方法 super(name, age); this.major = major; } say() { // 调用父类的成员方法 super.say(); console.log('I am teaching ' + this.major); } test() { // 调用父类的成员方法 super.say(); } } let t1 = new Teacher('zhangsan', 26, 'math'); t1.say(); t1.test(); Teacher.f(); // ---output--- // hello, my name is zhangsan, my age is 26 // I am teaching math // hello, my name is zhangsan, my age is 26 // hello, I am static method!
arguments & this 局部参数,局部this
局部参数
1 // Lexical arguments 2 // 局部参数 3 function testArgs() { 4 // arguments代表传入当前函数的参数 5 for (let arg of arguments) { 6 console.log(arg); 7 } 8 } 9 10 // hello 11 // 1 12 // 2.5 13 testArgs('hello', 1, 2.5);
局部this
// Lexical this // this是局部变量,代表person对象 let person = { _name: 'zhangsan', _friends: ['wangwu', 'tom', 'jack'], prints() { console.log('-----prints-----'); console.log(this); this._friends.forEach(name => { console.log(this._name + ' knows ' + name); }); console.log('-----prints-----'); } } // -----prints----- // { _name: 'zhangsan', // _friends: [ 'wangwu', 'tom', 'jack' ], // prints: [Function: prints] } // zhangsan knows wangwu // zhangsan knows tom // zhangsan knows jack // -----prints----- person.prints();
Enhanced Object Literals 增强对象语法
// Enhanced Object Literals // 增强对象语法 let name = 'zhangsan'; let tag = 'hello'; let obj = { f() { // 定义方法,原来的写法是f: function(){} console.log('this is a function'); }, name, // 缩写: name: name [tag + 'world']: 100 // 动态属性,用[]扩起来的地方是表达式 }; // { f: [Function: f], name: 'zhangsan', helloworld: 100 } console.log(obj);
Template Strings 字符串模板
// Template Strings // 字符串模板,使用``和${} let name = 'zhangsan'; let str = `hello, this is ${name}`; // hello, this is zhangsan console.log(str); let a = 10; let b = 20; // 10 + 20 = 30 console.log(`${a} + ${b} = ${a + b}`); // 使用\n换行 // today is a // nice day! console.log(`today is a \n nice day!`); // 直接在``中换行 // how are you // this days? console.log(`how are you this days?`);
Destructuring 解构
// Destructuring 解构 let [a, ,c] = [1, 5, 8]; // a = 1, c = 8 console.log(`a = ${a}, c = ${c}`); let person = { name: 'zhangsan', age: 25 }; let { name, age } = person; // name = zhangsan, age = 25 console.log(`name = ${name}, age = ${age}`); function test({name}) { console.log(`name = ${name}`); } // name = zhangsan test({name: 'zhangsan'}); // 默认参数 function r({x, y, z = 10}) { return x + y + z; } console.log(r({x: 1, y: 2, z: 3})); // 6 console.log(r({x: 1, y: 2})); // 13
Spread 展开属性
function test(x, ...y) { // y是长度可变的参数 console.log(y); return x + y.length; } // 这里x = 2, y是长度为3的数组[ 1, 'hello', 3 ] console.log(test(2, 1, 'hello', 3)); function add(x, y, z) { return x + y + z; } // ...[1, 2, 3]即将数组展开,将每个元素当作一个参数传入函数,x = 1, y = 2, z = 3 console.log(add(...[1, 2, 3]));
let & const
const a = 1; // a = 2; // 会报错 "TypeError: Assignment to constant variable." function f() { { let x; { const x = 'hello'; x = 'world'; // 会报错 "TypeError: Assignment to constant variable." } x = 'world'; let x = '123'; // 会报错 "SyntaxError: Identifier 'x' has already been declared" } } f();
Iterators + For..Of 遍历
// fibonacci是一个可遍历的对象 let fibonacci = { [Symbol.iterator]() { let pre = 0, cur = 1; return { next() { [pre, cur] = [cur, pre + cur]; return { done: false, value: cur } } } } } // 1 // 2 // 3 // 5 // 8 // 13 // 21 // 34 // 55 // 89 for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 100) break; console.log(n); }
Generators 迭代器
// 使用function*声明一个迭代器 //遇到yield语句,后面的代码会暂停执行,直到下次调用迭代器的next方法 function* g() { yield 'a'; yield 'b'; yield 'c'; return 'hello'; } let generator = g(); // { value: 'a', done: false } console.log(generator.next()); // { value: 'b', done: false } console.log(generator.next()); // { value: 'c', done: false } console.log(generator.next()); // { value: 'hello', done: true } console.log(generator.next()); // { value: undefined, done: true } console.log(generator.next()); var fibonacci = { [Symbol.iterator]: function*() { var pre = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } } } // 1 // 2 // 3 // 5 // 8 // 13 // 21 // 34 // 55 // 89 for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 100) break; console.log(n); }
Map + Set + WeakMap
let obj = {name: 'zhangsan'};
let s = new Set();
s.add('hello').add(obj).add('hello');
console.log(s.size); // 2
let map = new Map();
map.set('name', 'tom');
map.set('age', 25);
map.set(obj, obj); // object作为map的key
// name = tom, age = 25
console.log(`name = ${map.get('name')}, age = ${map.get('age')}`);
console.log(map.get(obj)); // { name: 'zhangsan' }
// WeakMap只能用Object作为key,不能使用基本数据类型如字符串,整型等
let wm = new WeakMap();
// wm.set('name', 'lily'); // 报错,TypeError: Invalid value used as weak map key
wm.set(obj, 'hello world');
console.log(wm.get(obj)); // hello world
obj = null;
console.log(wm.get(obj)); // undefined
console.log(wm.size); // undefined, WeakMap没有size
Promises 异步操作
function getData() { return new Promise((resolve, reject) => { // 模拟耗时的操作(网络,IO...) setTimeout(() => { resolve('this is data...'); }, 1000); }); } function test() { return new Promise((resolve, reject) => { setTimeout(() => { reject('error...'); }, 1000); }); } getData().then(data => { console.log(data); // this is data... }); test().then(() => { console.log('success'); }).catch(e => { console.log(e); // error... });
ES2016
node 支持:node v7.5.0 以上支持 100%。
- 新增规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
- 新增了数组实例的 includes 方法和指数运算符。
ES2017
node 支持:node v9.11.2 以上支持 100%。
Object.getOwnPropertyDescriptors()返回指定对象所有自身属性(非继承属性)的描述对象。Object.values和Object.entries供for...of循环使用。padStart()用于头部补全,padEnd()用于尾部补全。- 引入了 async 函数。
- 允许函数的最后一个参数有尾逗号。
- 引入 SharedArrayBuffer,允许 Worker 线程与主线程共享同一块内存。
ES2018
node 支持:node v12.4.0 以上支持 100%。
- 正则:引入s修饰符,使得.可以匹配任意单个字符,后行断言。
- 引入了“异步遍历器”(Async Iterator),为异步操作提供原生的遍历器接口。
- 模板字符串:遇到不合法的字符串转义,就返回
undefined,而不是报错。 - 对象引入扩展运算符。
Promise.finally()不管 Promise 对象最后状态如何,都会执行的操作。
ES2019
node 支持:node v12.4.0 以上支持 100%。
- 新增
trimStart()和trimEnd()。 toString()返回函数代码本身,以前会省略注释和空格,现在明确要求返回一模一样的原始代码。- 允许 catch 语句省略参数。
Array.prototype.sort()的默认排序算法必须稳定。- Symbol 提供了一个实例属性 description,直接返回 Symbol 的描述。
ES2020
node 支持:node v14.5.0 以上支持 100%。
- import() 动态异步加载。
- globalThis 打通所有环境。
String.prototype.matchAll()可以一次性取出所有匹配。不过,它返回的是一个遍历器(Iterator),而不是数组。- BigInt 大整数计算保持精度,无位数限制
BigInt('123') 123n typeof 123n === 'bigint'。 Promise.allSettled()只有等到所有这些参数实例都返回结果,不管是 fulfilled 还是 rejected,包装实例才会结束。- 链判断运算符 ?.
直接在链式调用的时候判断,左侧的对象是否为 null 或 undefined,如果是,就不再往下运算,而是返回 undefined
可用
obj?.prop // 对象属性
obj?.[expr] // 同上
func?.(...args) // 函数或对象方法的调用
不可用,报错
// 构造函数
new a?.()
new a?.b()
// 链判断运算符的右侧有模板字符串
a?.`{b}`
a?.b`{c}`
// 链判断运算符的左侧是 super
super?.()
super?.foo
// 链运算符用于赋值运算符左侧
a?.b = c
右侧不得为十进制数值
- Null 判断运算符 ??
只有运算符左侧的值为 null 或 undefined 时,才会返回右侧的值
let num = person.n ?? 100
?? 和 && || 同时用必须用括号表明优先级否则会报错
&& 和 || 的优先级孰高孰低,如果多个逻辑运算符一起使用,必须用括号表明优先级,否则会报错
ES2021
Promise.any()只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。replaceAll()一次性替换所有匹配'aabbcc'.replaceAll('b', '_') // 'aa__cc'。
map, forEach, filtermaplet nums = [1, 3, 5, 7, 9];console.log(nums); // [ 1, 3, 5, 7, 9 ]
// map方法传入一个函数,遍历数组中的每一个元素并将这个方法作用在元素上,最后返回一个新的数组,不改变原数组let arr1 = nums.map(i => i + 1);console.log(arr1); // [ 2, 4, 6, 8, 10 ]// map操作返回新的数组,所以下面返回falseconsole.log(arr1 === nums); // false
// map中传入的函数可以有两个参数,e代表遍历过程中当前的元素,i表示当前元素的索引,索引从0开始let arr2 = nums.map((e, i) => e + i);console.log(arr2); // [ 1, 4, 7, 10, 13 ]123456789101112forEachlet nums = [2, 4, 6, 8, 10];console.log(nums); // [ 2, 4, 6, 8, 10 ]
// forEach方法传入一个函数,该函数作用于数组中的每一个元素// forEach没有返回值,且不会修改原来的数组let arr = nums.forEach(e => e + 1);console.log(arr); // undefinedconsole.log(nums); // [ 2, 4, 6, 8, 10 ]
// 依次分行打印2,4,6,8,10nums.forEach(e => console.log(e));
// i: 0, e: 2// i: 1, e: 4// i: 2, e: 6// i: 3, e: 8// i: 4, e: 10nums.forEach((e, i) => console.log('i: ' + i + ', e: ' + e));123456789101112131415161718filterlet nums = [1, 2, 3, 4, 5, 6, 7, 8];console.log(nums); // [ 1, 2, 3, 4, 5, 6, 7, 8 ]
// filter传入一个函数,通过遍历数组找出满足该函数的所有元素并返回一个新数组let odds = nums.filter(e => e % 2 !== 0); // 过滤出所有奇数console.log(odds); // [ 1, 3, 5, 7 ]
let evens = nums.filter(e => e % 2 === 0); // 过滤出所有偶数console.log(evens); // [ 2, 4, 6, 8 ]
// i: 5, e: 6// i: 6, e: 7// i: 7, e: 8let bigs = nums.filter((e, i) => { if (e > 5) { console.log('i: ' + i + ', e: ' + e); }});123456789101112131415161718Class 类class Human { // 类的构造方法 constructor(name, age) { this.name = name; this.age = age; }
// 类的成员方法 say() { console.log('hello, my name is ' + this.name + ', my age is ' + this.age); }
static f() { console.log('hello, I am static method!'); }}
class Teacher extends Human { constructor(name, age, major) { // 调用父类的构造方法 super(name, age); this.major = major; } say() { // 调用父类的成员方法 super.say(); console.log('I am teaching ' + this.major); } test() { // 调用父类的成员方法 super.say(); }}
let t1 = new Teacher('zhangsan', 26, 'math');t1.say();t1.test();Teacher.f();
// ---output---// hello, my name is zhangsan, my age is 26// I am teaching math// hello, my name is zhangsan, my age is 26// hello, I am static method!1234567891011121314151617181920212223242526272829303132333435363738394041424344arguments & this 局部参数,局部this局部参数// Lexical arguments// 局部参数function testArgs() { // arguments代表传入当前函数的参数 for (let arg of arguments) { console.log(arg); }}
// hello// 1// 2.5testArgs('hello', 1, 2.5);12345678910111213局部this// Lexical this// this是局部变量,代表person对象let person = { _name: 'zhangsan', _friends: ['wangwu', 'tom', 'jack'], prints() { console.log('-----prints-----'); console.log(this); this._friends.forEach(name => { console.log(this._name + ' knows ' + name); }); console.log('-----prints-----'); }}
// -----prints-----// { _name: 'zhangsan',// _friends: [ 'wangwu', 'tom', 'jack' ],// prints: [Function: prints] }// zhangsan knows wangwu// zhangsan knows tom// zhangsan knows jack// -----prints-----person.prints();123456789101112131415161718192021222324Enhanced Object Literals 增强对象语法// Enhanced Object Literals// 增强对象语法let name = 'zhangsan';let tag = 'hello';let obj = { f() { // 定义方法,原来的写法是f: function(){} console.log('this is a function'); }, name, // 缩写: name: name [tag + 'world']: 100 // 动态属性,用[]扩起来的地方是表达式};
// { f: [Function: f], name: 'zhangsan', helloworld: 100 }console.log(obj);1234567891011121314Template Strings 字符串模板// Template Strings// 字符串模板,使用``和${}let name = 'zhangsan';let str = `hello, this is ${name}`;// hello, this is zhangsanconsole.log(str);
let a = 10;let b = 20;// 10 + 20 = 30console.log(`${a} + ${b} = ${a + b}`);
// 使用\n换行// today is a// nice day!console.log(`today is a \n nice day!`);
// 直接在``中换行// how are you// this days?console.log(`how are youthis days?`);12345678910111213141516171819202122Destructuring 解构// Destructuring 解构
let [a, ,c] = [1, 5, 8];// a = 1, c = 8console.log(`a = ${a}, c = ${c}`);
let person = { name: 'zhangsan', age: 25};let { name, age } = person;// name = zhangsan, age = 25console.log(`name = ${name}, age = ${age}`);
function test({name}) { console.log(`name = ${name}`);}// name = zhangsantest({name: 'zhangsan'});
// 默认参数function r({x, y, z = 10}) { return x + y + z;}console.log(r({x: 1, y: 2, z: 3})); // 6console.log(r({x: 1, y: 2})); // 131234567891011121314151617181920212223242526Spread 展开属性function test(x, ...y) { // y是长度可变的参数 console.log(y); return x + y.length;}// 这里x = 2, y是长度为3的数组[ 1, 'hello', 3 ]console.log(test(2, 1, 'hello', 3));
function add(x, y, z) { return x + y + z;}// ...[1, 2, 3]即将数组展开,将每个元素当作一个参数传入函数,x = 1, y = 2, z = 3console.log(add(...[1, 2, 3]));12345678910111213let & constconst a = 1;// a = 2; // 会报错 "TypeError: Assignment to constant variable."
function f() { { let x; { const x = 'hello'; x = 'world'; // 会报错 "TypeError: Assignment to constant variable." } x = 'world'; let x = '123'; // 会报错 "SyntaxError: Identifier 'x' has already been declared" }}f();123456789101112131415Iterators + For..Of 遍历// fibonacci是一个可遍历的对象let fibonacci = { [Symbol.iterator]() { let pre = 0, cur = 1; return { next() { [pre, cur] = [cur, pre + cur]; return { done: false, value: cur } } } }}
// 1// 2// 3// 5// 8// 13// 21// 34// 55// 89for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 100) break; console.log(n);}1234567891011121314151617181920212223242526272829Generators 迭代器// 使用function*声明一个迭代器//遇到yield语句,后面的代码会暂停执行,直到下次调用迭代器的next方法function* g() { yield 'a'; yield 'b'; yield 'c'; return 'hello';}let generator = g();// { value: 'a', done: false }console.log(generator.next());// { value: 'b', done: false }console.log(generator.next());// { value: 'c', done: false }console.log(generator.next());// { value: 'hello', done: true }console.log(generator.next());// { value: undefined, done: true }console.log(generator.next());
var fibonacci = { [Symbol.iterator]: function*() { var pre = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } }}
// 1// 2// 3// 5// 8// 13// 21// 34// 55// 89for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 100) break; console.log(n);}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748Map + Set + WeakMaplet obj = {name: 'zhangsan'};let s = new Set();s.add('hello').add(obj).add('hello');console.log(s.size); // 2
let map = new Map();map.set('name', 'tom');map.set('age', 25);map.set(obj, obj); // object作为map的key// name = tom, age = 25console.log(`name = ${map.get('name')}, age = ${map.get('age')}`);console.log(map.get(obj)); // { name: 'zhangsan' }
// WeakMap只能用Object作为key,不能使用基本数据类型如字符串,整型等let wm = new WeakMap();// wm.set('name', 'lily'); // 报错,TypeError: Invalid value used as weak map keywm.set(obj, 'hello world');console.log(wm.get(obj)); // hello worldobj = null;console.log(wm.get(obj)); // undefinedconsole.log(wm.size); // undefined, WeakMap没有size12345678910111213141516171819202122Promises 异步操作function getData() { return new Promise((resolve, reject) => { // 模拟耗时的操作(网络,IO...) setTimeout(() => { resolve('this is data...'); }, 1000); });}
function test() { return new Promise((resolve, reject) => { setTimeout(() => { reject('error...'); }, 1000); });}
getData().then(data => { console.log(data); // this is data...});
test().then(() => { console.log('success');}).catch(e => { console.log(e); // error...});————————————————版权声明:本文为CSDN博主「yubo_725」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/yubo_725/article/details/81099338

浙公网安备 33010602011771号