简单总结ES6、ES7、ES8、ES9、ES10、ES11、ES12新特性

1. ES6 (ECMAScript 2015)

1.1. let和const

let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
const 用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。

{
    var a = 1
    let b = 2
    const c = 3
}

console.log(a)  // 1
console.log(b) // Uncaught ReferenceError: b is not defined
console.log(c) // Uncaught ReferenceError: c is not defined

const d = 4
d = 5  // Uncaught TypeError: Assignment to constant variable.

注意:const定义的对象属性是否可以改变?
可以,因为对象是引用类型,const仅保证指向对象的指针不发生改变,而修改对象的属性不会改变对象的指针,所以是被允许的

1.2. 类 (class)
class Bird {
  constructor(name) {
    this.name = name;
  }
  fly() {
    console.log('fly...');
  }
}
const eagle = new Bird('Eagle')
eagle.fly()  // fly...
1.3. 模块化(ES Module)

支持通过import引入类和方法

// A.js
export const add = (a, b) => a + b

// B.js
import { add } from './A'
console.log(add(1, 2))  // 3
1.4. 箭头函数 (Arrow Function)
const add = (a, b) => a + b;
add(1, 2) // 3
1.5. 函数参数默认值
function func(name = 'danny',age = 23){
    // code
}
1.6. 模板字符串 (Template String)

通过反引号`构造模板字符串

let name = 'danny'
let age = 23
let str = `My name is ${name},I am ${age} years old.`
console.log(str) // My name is danny,I am 23 years old.
1.7. 解构赋值(Destructuring)

通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

let arr = [0,1,2]
let [a,b,c] = arr
console.log(a) // 0
console.log(b) // 1
console.log(c) // 2

let {name,age} = {name:'danny',age:23}
console.log(name) // danny
console.log(age) // 23

let [a, b, c, d, e] = 'hello';
console.log(a) // a = 'h'
console.log(b) // b = 'e'
console.log(c) // c = 'l'
console.log(d) // d = 'l'
console.log(e) // e = 'o'
1.8. 延展操作符(Spread Operator)
let a = [...'hello world']; // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
1.9. 对象属性简写
let name = 'danny';
let person = {
    name: name;
};

//等同于
let name = 'danny';
let person = {
    name;
};
1.10. Promise

防止回调地狱

// 声明一个Promise对象
let promise = new Promise(function(resolve, reject) {
  // ... some code

  if (success){
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(
    () => { console.log('this is success callback') }
).catch(
    (err) => { console.log(err) }
).then(
    ...
).catch(
    ...
)

2. ES7 (ECMAScript 2016)

2.1. Array.prototype.includes()
["a","b"].includes("a") // true
["a","b"].includes("c") // false
2.2. 指数操作符
2**10; // 1024

3. ES8 (ECMAScript 2017)

3.1.async/await
async getData(){
    const res = await api.getTableData(); // await 异步任务
    // do something    
}
3.2. Object.values()
Object.values({a: 1, b: 2, c: 3}); // [1, 2, 3]
3.3. Object.entries()
Object.entries({a: 1, b: 2, c: 3}); // [["a", 1], ["b", 2], ["c", 3]]
3.4. String padding
// padStart
'hello'.padStart(10); // "     hello"
// padEnd
'hello'.padEnd(10) "hello     "
3.5. 自动忽略函数参数列表/对象字面量/数组结尾处逗号
function foo(param1, param2,) {}
let obj = {first: 'Jane',last: 'Doe',}
let arr = ['red','green', 'blue',]
3.6. Object.getOwnPropertyDescriptors()

返回指定对象所有自身属性(非继承属性)的描述对象。
该方法的引入目的,主要是为了解决Object.assign()无法正确拷贝 get 属性和 set 属性的问题。

const clone = Object.create(Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj));
3.7. SharedArrayBuffer

SharedArrayBuffer 对象用来表示一个通用的,固定长度的原始二进制数据缓冲区,类似于 ArrayBuffer 对象,它们都可以用来在共享内存(shared memory)上创建视图。与 ArrayBuffer 不同的是,SharedArrayBuffer 不能被分离。

new SharedArrayBuffer(length)

3.8. Atomics

Atomics 对象提供了一组静态方法对 SharedArrayBufferArrayBuffer 对象进行原子操作。、


4. ES9 (ECMAScript 2018)

4.1. 异步迭代

await可以和for...of循环一起使用,以串行的方式运行异步操作

async function process(array) {
  for await (let i of array) {
    // doSomething(i);
  }
}
4.2. Promise.finally()
Promise.resolve().then().catch(e => e).finally();
4.3. Rest/Spread 属性

可以简单理解rest为收集,spread 为展开

用于对象解构的rest 操作符,目前这个操作符只能在数组解构和参数定义中使用

const obj = {foo: 1, bar: 2, baz: 3};
const {foo, ...rest} = obj;
console.log(rest) // {bar: 2, baz: 3}

如果你正在使用对象解构来处理命名参数,rest 操作符让你可以收集所有剩余参数

function func(param1, param2, ...rest) { // rest operator
    console.log('All parameters: ',param1, param2, ...rest);  // spread operator
}

fuc(1,2,3,4,5)  // All parameters:  1 2 3 4 5

对象字面量中的 spread 操作符,目前这个操作符只能用于数组字面量和在函数方法中调用。

 const obj = {foo: 1, bar: 2, baz: 3};
 {...obj, qux: 4} // { foo: 1, bar: 2, baz: 3, qux: 4 }
4.4. 正则表达式s标记(dotAll)

ES9之前,在正则中.可以匹配任意字符,除了换行符\n

/hello.es9/.test('hello\nes9')  // false

/hello.es9/.test('hello\tes9')  // true

ES9引入了dotAll模式,通过使用标记s选项,.就可以匹配换行符。

/hello.es9/s.test('hello\nes9')  // true
4.5. 正则表达式命名捕获组(Named capture groups)

ES9之前,正则表达式中小括号匹配的分组是通过索引编号的

const reg = /(\d{4})-(\d{2})-(\d{2})/u;
const matched = reg.exec('2021-01-05');
matched[0];  // 2021-01-05
matched[1];  // 2021
matched[2];  // 01
matched[3];  // 05

ES9允许命名捕获组使用符号?<name>,可以指定小括号中匹配内容的名称放在groups里,这样可以提高代码的可读性。

const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const matched = reg.exec('2021-01-05');
matched.groups.year;   // 2021
matched.groups.month;  // 01
matched.groups.day;    // 05

//命名捕获组也可以使用在replace()方法中。例如将日期转换为“年月日”格式:
const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
'2018-12-31'.replace(reg, '$<year>年$<month>月$<day>日');  // 2018年12月31日
4.6. 反向断言 (lookbehind)

(?=pattern):正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。

(?!pattern):正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。

(?<=pattern): 反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。

(?<!pattern):反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。

4.7. 正则表达式 Unicode 转义

Unicode属性转义,形式为\p{...}和\P{...},在正则表达式中使用标记u(unicode) 选项。

/^\p{White_Space}+$/u.test(' ') // 匹配空格 
/^\p{Script=Greek}+$/u.test('μετά') // 匹配希腊字母
/^\p{Script=Latin}+$/u.test('Grüße') // 匹配拉丁字母 
/^\p{Surrogate}+$/u.test('\u{D83D}') // 匹配单独的替代字符

5. ES10 (ECMAScript 2019)

5.1. Array.flat()和Array.flatMap()

flat()

[1, 2, [3, 4]].flat(Infinity); // [1, 2, 3, 4]

flatMap()

[1, 2, 3, 4].flatMap(a => [a**2]); // [1, 4, 9, 16]
5.2. String.trimStart()和String.trimEnd()

去除字符串首尾空白字符

'   hello'.trimStart()   // 'hello'
'hello   '.trimEnd()     // 'hello'
5.3. String.prototype.matchAll

matchAll()方法返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。

const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';

const array = [...str.matchAll(regexp)];

console.log(array[0]);
// expected output: Array ["test1", "e", "st1", "1"]

console.log(array[1]);
// expected output: Array ["test2", "e", "st2", "2"]
5.4. Symbol.prototype.description

用来获取Symbol字符串的描述

let sy = Symbol('hello world')
console.log(sy.description)  // 'hello world'
5.5. Object.fromEntries()

Object.entries() 是将对象转成一个自身可枚举属性的键值对数组。同样,我们也可以通过 Object.fromEntries()把键值对数组转成了对象。

// 将数组转成对象
const array = [['key 1', 'value 1'],['key 2', 'value 2']
Object.fromEntries(array)   // { key 1: "value 1", key 2: "value 2"}

//将 Map 转成对象
const map = new Map()
map.set('key 1', 'value 1')
map.set('key 2', 'value 2')
Object.fromEntries(map)   // { key 1: "value 1", key 2: "value 2"}
5.6. 可选 Catch Binding

允许开发人员在catch块中,不使用error参数的情况下使用try/catch

// ES10 之前使用
try {
  // some code
}
catch (err) {
  // error handling code
}

// 现在使用ES10这样的try / catch:
try  {
  // some code
}
catch {
  // error handling code
}

6. ES11(ECMAScript 2020)

6.1. 私有属性

使用#修饰私有字段

class Person {
  name
  #age
  constructor(name, age) {
    this.name = name
    this.#age = age
  }
}

const person= new Person('danny', 22)
console.log(person.name)  // danny
console.log(person.#age)  // Uncaught SyntaxError: Private field '#age' must be declared in an enclosing class

6.2. Nullish coalescing Operator(空值处理)

表达式在 ??的左侧 运算符求值为undefined或null,返回其右侧

let user = {
    u1: 0,
    u2: false,
    u3: null,
    u4: undefined
    u5: '',
}
let u2 = user.u2 ?? '用户2'  // false
let u3 = user.u3 ?? '用户3'  // 用户3
let u4 = user.u4 ?? '用户4'  // 用户4
let u5 = user.u5 ?? '用户5'  // ''  
6.3. 可选链(Optional chaining)

使用 ?.检测不确定的中间节点

let user = {}
let u1 = user.childer.name // TypeError: Cannot read property 'name' of undefined
let u2 = user.childer?.name // undefined
6.4. Promise.allSettled

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilledrejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。

当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个promise的结果时,通常使用它。

相比之下,Promise.all() 更适合彼此相互依赖或者在其中任何一个reject时立即结束。

const promises = [
  fetch('/api-1'),
  fetch('/api-2'),
  fetch('/api-3'),
];

await Promise.allSettled(promises)
  .then((results) => results
    .forEach((result) => console.log(result.status)))
6.5. 动态import

动态导入hello模块进行使用,import(路径)的得到的是一个Promise对象,使用then获取成功的模块。

// a.js
export const hello = () => {
  alert('hello');
};

// b.js
const btn = document.querySelector('#btn');
btn.onclick = () => {
  import('./a.js').then(module => {
    module.hello();
  });
};
6.6. BigInt

ES11 引入了新的数据类型 BigInt类型 大整型,进行更大的数值运算。
注意:大整型只能和大整型进行运算

// 使用方法:
// 1.在普通的整型数后加n
let n = 666n;
console.log(n, typeof n);  //666n "bigint"

// 2.使用BigInt()函数
let n = 666;
console.log(BigInt(n));  // 666n
6.7. 绝对全局对象(globalThis)

字面意思为全局的this, globalThis始终指向全局对象(无论运行环境node、浏览器等)

console.log(globalThis)  //Window {window: Window, self: Window, document: document, name: "", location: Location, …}

7. ES12(ECMAScript2021)

7.1. replaceAll

返回一个全新的字符串,所有符合匹配规则的字符都将被替换掉

const str = 'hello world';
str.replaceAll('o', 'b');   // "hellb wbrld"
7.2. Promise.any

Promise.any() 接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise

const promise1 = new Promise((resolve, reject) => reject('我是失败的Promise_1'));
const promise2 = new Promise((resolve, reject) => reject('我是失败的Promise_2'));
const promiseList = [promise1, promise2];
Promise.any(promiseList)
.then(values=>{
  console.log(values);
})
.catch(e=>{
  console.log(e);
});   // AggregateError: All promises were rejected


const promise3 = new Promise((resolve, reject) => reject('我是失败的Promise_3'));
const promise4 = new Promise((resolve, reject) => resolve('我是成功的Promise_4'));
const promiseList1 = [promise3, promise4];
Promise.any(promiseList1)
.then(values=>{
  console.log(values);
})
.catch(e=>{
  console.log(e);
});    //  我是成功的Promise_4
7.3. WeakRefs

使用WeakRefs的Class类创建对对象的弱引用(对对象的弱引用是指当该对象应该被GC回收时不会阻止GC的回收行为)

7.4. 逻辑运算符和赋值表达式

逻辑运算符和赋值表达式,新特性结合了逻辑运算符(&&,||,??)和赋值表达式而JavaScript已存在的复合赋值运算符有:

操作运算符:+= -= *= /= %= **=
位操作运算符:&= ^= |=
按位运算符:<<= >>= >>>=

现有的的运算符,其工作方式都可以如此来理解
表达式:a op= b 等同于:a = a op b
逻辑运算符和其他的复合赋值运算符工作方式不同
表达式:a op= b等同于:a = a op (a = b)

a ||= b
//等价于
a = a || (a = b)

a &&= b
//等价于
a = a && (a = b)

a ??= b
//等价于
a = a ?? (a = b)

为什么不再是跟以前的运算公式a = a op b一样呢,而是采用a = a op (a = b)。因为后者当且仅当a的值为false的时候才计算赋值,只有在必要的时候才执行分配,而前者的表达式总是执行赋值操作

7.5. 数字分隔符

数字分隔符,可以在数字之间创建可视化分隔符,通过_下划线来分割数字,使数字更具可读性

const money1 = 1_000_000_000;
//等价于
const money2 = 1000000000;

money1  === money2  // true
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 154,867评论 4 353
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 65,736评论 1 283
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 104,751评论 0 235
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,205评论 0 201
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,500评论 3 283
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,058评论 1 201
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,484评论 2 305
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,175评论 0 190
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,811评论 1 234
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,157评论 2 237
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,681评论 1 254
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,045评论 2 245
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,576评论 3 227
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,907评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,613评论 0 190
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,045评论 2 260
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,014评论 2 256

推荐阅读更多精彩内容