Javascript[ECMAScript] ES6、ES7、ES8、ES9、ES10、ES11、ES12、ES13、ES14[2023]新特性

本文主要是介绍Javascript[ECMAScript] ES6、ES7、ES8、ES9、ES10、ES11、ES12、ES13、ES14[2023]新特性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

# 前言
鉴于找不到ES6-ES14 的新特性集合,所以有了这篇文章,后续会持续更新每年的新特性
# 背景

## JS1.1(1997)
[第一版基于Netscape Navigator 3.0中实现的JAVASCRIPT 1.1](https://web.archive.org/web/19970614042441/http://home.netscape.com/eng/mozilla/3.0/handbook/javascript/index.html)
## JS1.2(1999)
[基于Netscape Navigator 4.0中实现的JavaScript 1.2。添加了正则表达式、更好的字符串处理、新的控制语句、Try/Catch异常处理、更严格的错误定义、数字输出格式以及其他增强功能](https://web.archive.org/web/19990420172150/http://developer.netscape.com/docs/manuals/communicator/jsref/index.htm)
## ES5(2015)
### 1.严格模式

```js
use strict
```
### 2.Object
-   getPrototypeOf,返回一个对象的原型
-   getOwnPropertyDescriptor,返回某个对象自有属性的属性描述符
-   getOwnPropertyNames,返回一个数组,包括对象所有自由属性名称集合(包括不可枚举的属性)
-   hasOwnProperty,给定属性存在于对象实例中,返回 true
-   isPrototypeOf,在原型链中出现过的原型,返回 true
-   create,创建一个拥有指定原型和若干指定属性的对象
-   defineProperty,为对象定义一个新属性,或者修改已有的属性,并对属性重新设置 getter 和 setter,这里可以被用作数据绑定的对象劫持用途
-   defineProperties,在一个对象上添加或修改一个或者多个自有属性,与 defineProperty 类似
-   seal,锁定对象,阻止修改现有属性的特性,并阻止添加新属性,但是可以修改已有属性的值
-   freeze,冻结对象,阻止对对象的一切操作和更改,冻结对象将变成只读
-   preventExtensions,让一个对象变得不可以扩展,也就是不能再添加新的属性
-   isSealed,判断对象是否被锁定
-   isFrozen,判断对象是否被冻结
-   isExtensible,判断对象是否可以被扩展
-   keys,返回一个由给定对象的所有可以枚举自身属性的属性名组成的数组
### 3.Array
-   Array.isArray,确定某个值到底是不是数组,不管它在哪个全局执行环境中创建
-   push,接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度
-   pop,在数组尾部移除最后一项,减少数组的 length 值,然后返回移除的项
-   shift,移除数组中的第一项并返回该项,同时将数组长度减 1
-   unshift,在数组前端添加任意个项,并返回新数组的长度
-   reverse,反转数组项的顺序,返回排序后的数组
-   sort,默认情况下,按升序排序数组项,返回排序后的数组
-   concat,创建当前数组的一个副本,将接收到的参数添加到这个副本的末尾,返回新构建的数组
-   join,用指定的字符拼接数组,返回拼接好的字符串
-   slice,基于当前数组中的一个或多个创建一个新数组,不影响原始数组
-   splice,根据传入参数不同,可以删除、插入、替换数组元素,返回一个数组,该数组中包含从原始数组中删除的项,如果没有删除任何项,则返回空数组
-   indexOf,返回根据给定元素找到的第一个索引值,如果不存在则返回 -1
-   lastIndexOf,返回指定元素在数组中的最后一个索引值,如果不存在则返回 -1
-   every ,对数组中的每一项运行给定函数 ,如果该函数对每一项都返回 true,则返回 true
-   filter,对数组中的每一项运行给定函数 ,返回该函数会返回 true 的项组成的数组
-   forEach,对数组中的每一项运行给定函数,没有返回值
-   map,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
-   some,对数组中的每一项运行给定函数,如果函数对任一项返回 true,则返回 truereduce,接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终缩减为一个值
-   reduceRight,接收一个函数作为累加器,数组中的每个值(从右到左)开始缩减,最终缩减为一个值
### 4.String
-   charAt,访问字符串中特定字符,返回给定位置的字符
-   charCodeAt,访问字符串中特定字符,返回给定位置的字符的字符编码
-   concat,将一个或多个字符串拼接起来,返回拼接得到的新字符串
-   match,查找匹配的字符串,返回一个数组
-   search,查找匹配的字符串,返回匹配项的索引,没有找到,返回 -1
-   replace,替换字符串
-   split,基于指定的分隔符将一个字符串分割成多个字符串,将结果放在一个数组中,并返回
-   trim,创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果
-   localeCompare,比较两个字符串
-   slice,返回被操作字符串的一个子字符串
-   substr,返回被操作字符串的一个子字符串
-   substring,返回被操作字符串的一个子字符串

注意:slice、substr、substring 都接受一个或两个参数,第一个参数指定字符串的开始位置,第二个参数表示子字符串到哪里结束,slice 和 substring 的第二个参数指定的是子字符串的最后一个字符后面的位置,substr 第二个参数指定的是返回的字符个数,如果没有传递第二个参数,则将字符串的末尾作为结束位置。
### 5.Function
-   arguments.callee,该属性是一个指针,指向拥有这个 arguments 对象的函数
-   arguments.caller,该属性保存着调用当前函数的函数的引用
-   apply,在特定的作用域中调用函数,第一个参数是在其中运行函数的作用域,第二个是参数数组
-   call,在特定的作用域中调用函数,第一个参数是在其中运行函数的作用域,其余参数直接传递给函数
-   bind,创建一个函数的实例,其 this 值会被绑定到传给 bind 函数的值
### 6.JSON
-   JSON.parse,解析字符串为 JSON 对象
-   JSON.stringify,解析 JSON 对象为字符串
-   JSON.valueOf,获取某个JSON 对象中的值
-   JSON.toString,被调用时,会调用 Object 原型上的 toString 方法,会获的 JSON 对象的值并转为字符串,如果没有具体的值,则返回原型数组
-   JSON.toLocaleString,也是Object 原型上的方法,经常会返回与 toString 相同内容,但是对于 Date 对象,则会返回格式化的时间字符串
### 7.其他
-   Date.now,返回当前时间戳
-   Date.toJSON,将 Date 对象转换为字符串,格式为 JSON 日期
-   Math.min,确定一组数值中的最小值
-   Math.max,确定一组数值中的最大值
-   Math.random,返回大于 0 小于 1 的一个随机数
-   Number.prototype.toFixed,按照指定的小数位返回数值的字符串表示
-   
## ES6(2015)
### 1. 类(class)

```js
class Man {
  constructor(name) {
    this.name = '你好世界';
  }
  console() {
    console.log(this.name);
  }
}
const man = new Man('你好世界');
man.console(); // 你好世界
```

### 2. 模块化(ES Module)

```js
// 模块 A 导出一个方法
export const sub = (a, b) => a + b;
// 模块 B 导入使用
import { sub } from './A';
console.log(sub(1, 2)); // 3
```

### 3. 箭头(Arrow)函数

```js
const func = (a, b) => a + b;
func(1, 2); // 3
```

### 4. 函数参数默认值

```
function foo(age = 25,){ // ...}
```

### 5. 模板字符串

```js
const name = '你好世界';
const str = `Your name is ${name}`;
```

### 6. 解构赋值

```js
let a = 1, b= 2;
[a, b] = [b, a]; // a 2  b 1
```

### 7. 延展操作符

```js
let a = [...'hello world']; // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
```

### 8. 对象属性简写

```js
const name='你好世界',
const obj = { name };
```

### 9. Promise
Promise 代表一个异步操作的执行返回状态,这个执行返回状态在 Promise 对象创建时是未知的,它允许为异步操作的成功或失败指定处理方法。

#### 9.1 Promise 的状态有三种:

-   Fulfilled,表示 Promise 执行成功
-   Rejected,表示 Promise 执行失败
-   Pending,表示 Promise 正在执行中

#### 9.2 Promise 对象有两个特点:

-   对象的状态不受外界影响
-   一旦状态改变就不会再变,任何时候都可以得到这个结果

#### 9.3 缺点:

-   无法取消 Promise,一旦新建它就会立即执行,无法中途取消
-   如果不设置回调函数,Promise 内部抛出的错误不会反应到外部
-   当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚开始还是即将完成)

#### 9.4 基本用法:

```js
var promise = new Promise(function(resolve, reject) {
    // ... some code

    if ( /*异步操作成功*/ ) {
        resolve(value)
    } else {
        reject(error)
    }
})

promise.then(function(value) {
    // success
}, function(error) {
    // failure
})
```

#### 9.5 Promise 实例方法:

-   Promise.prototype.then(),为 Promise 实例添加状态改变时的回调函数,返回一个新的 Promise 实例
-   Promise.prototype.catch(),用于指定发生错误时的回调函数,返回一个新的 Promise 实例
-   Promise.prototype.done(),总是处于回调链的尾端,保证捕捉到任何可能出现的错误
-   Promise.prototype.finally(),用于指定不管 Promise 对象最后状态如何都会执行的操作。

finally 与 done 的最大区别在于:finally 接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。

#### 9.6 Promise 对象方法:

-   Promise.all(),将多个 Promise 实例包装成一个新的 Promise 实例。

```js
var p = Promise.all([p1, p2, p3])
```

p 的状态由 p1,p2,p3 决定:

第一,只有 p1,p2,p3 的状态都编程 Fulfilled,p 的状态才会变成 Fulfilled,此时p1,p2,p3 的返回值组成一个数组,传递给 p 的回调函数。

第二,只要 p1,p2,p3 中有一个被 Rejected,p 的状态就变成 Rejected,此时第一个被 Rejected 的实例的返回值会传递给 p 的回调函数

-   Promise.race(),将多个 Promise 实例包装成一个新的 Promise 实例。

```js
var p = Promise.race([p1, p2, p3])
```

只要 p1,p2,p3 中有一个实例率先改变状态,p 的状态就跟着改变,那个率先改变的 Promise 实例的返回值就传递给 p 的回调函数。

-   Promise.resolve(),将现有对象转为 Promise 对象,状态为 Resolved
-   Promise.reject(),将现有对象转为 Promise 对象,状态为 Rejected

```js
Promise.resolve().then(() => { console.log(2); });
console.log(1);
// 先打印 1 ,再打印 2
```

### 10. let和const

```js
let name = '你好世界';
const arr = [];
```

### 11. 数组的新特性
ES6 为数组内置对象添加了较多的新特性,主要包括 ... 复制数组和新增的数组 API。

```
const arr = [1, 2, 3]
const newArr = [...arr]  //[1, 2, 3]
```

注意:这里 ... 进行的数组复制是**浅拷贝**。

ES6 数组的新增方法:

-   Array.from,用于将类数组对象(包括 [array-like object] 和可遍历对象)转化为真正的数组
-   Array.of,可以将传入的一组参数值转换为数组
-   Array.prototype.copyWithin,可以在当前数组内部将指定位置的数组项复制到其他位置,然后返回当前数组,使用 copyWithin 方法会修改当前数组
-   Array.prototype.fill,使用给定值,填充一个数组,会改变原来的数组
-   Array.prototype.find,用于找出第一个符合条件的数组元素,有点类似于 filter
-   Array.prototype.findIndex,用来返回某个特定数组元素在数组中的位置
-   Array.prototype.entries,对数组中键值对进行遍历
-   Array.prototype.keys,对数组键名进行遍历
-   Array.prototype.values,对数组键值进行遍历
-   for...of 循环进行遍历
-   Array.prototype[Symbol.iterator],用来获取遍历数组对象的迭代器

### 11. 函数参数
ES6 对函数参数进行了新的设计,主要添加了默认参数、不定参数和扩展参数:

```js
// 默认参数
function sayHi(name = 'zhangsan') {
    console.log(`Hello ${name}`)
}
sayHi() // Hello zhangsan


// 不定参数
function sayHi(...name) {
    console.log(name.reduce((a, b) => `Hello ${a} ${b}`))
}
sayHi('zhangsan', 'lisi') 


// 扩展参数
let name = ['zhangsan', 'lisi']
function sayHi(name1, name2) {
    console.log(`Hello ${name1} ${name2}`)
}
sayHi(...name) 
```

不定参数和扩展参数可以认为恰好是相反的两个模式,不定参数是使用数组来表示多个参数,扩展参数则是将多个参数映射到一个数组。

需要注意:不定参数的 ... 和数组复制的 ... 是有区别的,不定参数可以使用函数的形参来表示所有的参数组成的列表。以前的 arguments 变量也有类似的作用,但是 arguments 不是真正的数组,除了存放参数的列表外,arguments 还有 length 属性,严格来说 arguments 是一个类数组对象,而不定参数则是一个完全的数组,这也是不定参数相对于 arguments 的优势,更加方便我们使用,所以建议使用不定参数来代替 arguments。

### 12. 集合类型 Map + Set + WeakMap + WeakSet
#### 12.1 Set

Set 本身是一个构造函数 ,用来生成 Set 数据结构,Set 类似于数组(但它不是数组),Set 的成员的值都是唯一的,没有重复的值,也常用它来去重(不可以传递对象)。像 Set 加入值的时候,不会发生类型转换,所以 5 和 “5” 是两个不同的值。

```
const arr = new Set([1, 2, 3, 4, 5, 5, 5, 5])

console.log(arr)  //[1, 2, 3, 4, 5]
console.log(arr.size)  //5 
```

操作方法:

-   add(value),添加某个值,返回 Set 结构本身
-   delete value,删除某个值,返回一个布尔值,表示删除是否成功
-   has(value),返回一个布尔值,表示该值是否为 Set 成员
-   clear(),清除所有成员,没有返回值

遍历方法:

-   keys(),返回键名的遍历器
-   values(),返回键值的遍历器
-   entries(),返回键值对的遍历器
-   forEach(),使用回调函数遍历每个成员

#### 12.2 WeakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合,但是,它与 Set 有两个区别:

第一,WeakSet 的成员只能是对象,而不能是其他类型的值。

第二,WeakSet 中的对象都是弱引用,即垃圾回收机制 不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不在引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还存在于 WeakSet 中。因此 ES6 规定 WeakSet 不可遍历。  


#### 12.3 Map

传统的 JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是只能用字符串当做键,这给它的使用带来了很大的限制,而 ES6 提供了 Map 数据结构,它类似于对象,也是键值对的集合,但是“键” 的范围不限于字符串,各种类型的值(包括对象)都可以当做键。也就是说,Object 结构提供了“字符串-值”的对应,Map 结构提供了“值-值”的对应,是一种更完善的 Hash 结构实现。Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。

操作方法:

-   set(key, value),设置 key 所对应的键值,返回整个 Map 结构 ,如果 key 已经有值,则键值会被更新,否则就生成该键
-   get(key),读取 key 对应的键值,如果在好不到 key,则返回 undefined
-   has(key),返回一个 布尔值,表示某个键是否在 Map 数据结构中
-   delete(key),删除某个键,返回 true,如果删除失败,则返回 false
-   clear(),清除所有成员,没有返回值

遍历方法:

-   keys(),返回键名的遍历器
-   values(),返回键值的遍历器
-   entries(),返回所有成员的遍历器
-   forEach(),遍历 Map 的所有成员

#### 12.4 WeakMap

WeakMap 结构与 Map 结构类似,也用于生成键值对的集合,但 WeakMap 与 Map 有两个个区别:

第一,WeakMap 只接受对象作为键名(null 除外),不接受其他类型的值作为键名。

第二,WeakMap 的键名所指向的对象不计入垃圾回收机制。它的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内,因此,只要所引用的对象的其他引用被清除了,垃圾回收机制就会释放该对象所占用的内存。也就是说, 一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。基本上,如果要想对象中添加数据又不想干扰垃圾回收机制,便可以使用 WeakMap。一个典型的应用场景是,在网页的 DOM 元素上添加数据时就可以使用 WeakMap 结构,当该 DOM 元素被清除,其对应的 WeakMap 记录就会自动被移除。

注意:WeakMap 的专用场景就是它的键所对应的对象可能会在将来消失,WeakMap 结构有助于防止内存泄露。但是,WeakMap 弱引用的只是键名而不是键值,键值依然是正常引用的。

### 13. Symbol 类型
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值,它是 JavaScript 语言的第 7 种数据类型,前 6 种分别是:Undefined、Null、Boolean、String、Number 和 Object。

Symbol 值通过 Symbol 函数生成,一般作为属性键值,并且能避免对象属性键的命名冲突。也就是说,对象的属性名现在可以有两种类型:一种是原来就有的字符串,另一种就是新增的 Symbol 类型。只要属性名属于 Symbol 类型,就是独一无二的,可以保证不会与其他属性名产生冲突。

```js
let s = Symbol('foo')

typeof s  //"symbol"
```

注意:

Symbol 函数前不能使用 new 命令,否则会报错,这是因为生产的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。

Symbol 函数的参数只表示对当前 Symbol 值的描述,因此相同参数的 Symbol 函数的返回值是不相等的。

Symbol 值作为对象属性名时不能使用点运算符:

```js
let s = Symbol()

let obj = {
    [s]: function() {
        console.log('Hello')
    }
}

obj[s]()  // 'Hello'
```

Symbol 做为属性名,该属性不会出现在 for...in,for...of 循环中,也不会被 Object.keys()、Object.getOwnpropertyNames() 返回,但它也不是私有属性,Object.getOwnPropertySymbols() 可以获取指定对象的所有 Symbol 属性名。 Object.getOwnPropertySymbols() 返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

### Proxy
Proxy 用于修改某些操作的默认行为,可以用来拦截某个对象的属性访问方法,然后重载对象的 “ . ” 运算符。

Proxy 可以理解成在目标对象前架设一个“拦截”层,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。

```js
let object = new Proxy({}, {
    get: function(target, key, receiver) {
        console.log(`getting ${key}`)
        return Reflect.get(target, key, receiver)
    },
    set: function(target, key, value, receiver) {
        console.log(`setting ${key}`)
        return Reflect.set(target, key, value, receiver)
    }
})
```

对比 Object.defineProperty 方法:

```js
let object = {},
    value

Object.defineProperty(object, 'value', {
    get: function() {
        console.log('getting value')
        return value
    },
    set: function(newValue) {
        value = newValue
        console.log('setting: ' + newValue)
    },
    enumerable: true,
    configurable: true
})
```
### Reflect
Reflect 对象的设计目的有以下几个:

第一,将 Object 对象的一些明显属于语言内部的方法(如 Object.defineProperty)放到 Reflect 对象上,现阶段,某些方法同时在 Object 和 Reflect 对象上部署,未来新的方法只在 Reflect 对象上部署。也就是说,从 Reflect 对象上可以获得语言内部的方法。

第二,修改某些 Object 方法的返回结果,让其变得更加合理。

第三,让 Object 操作都编程函数行为,某些 Object 操作是命令式,比如 name in obj 和 delete obj [name],而 Reflect.has(obj, name) 和 Reflect.deleteProperty(obj, name) 让它们变成了函数行为。

第四,Reflect 对象的方法与 Proxy 对象的方法一一对应,只要是 Proxy 对象的方法,就能在 Reflect 对象上找到对应的方法,这就是 Proxy 对象可以方便的调用对应的 Reflect 方法来完成默认行为,作为修改行为的基础。也就是说,无论 Proxy 怎么修改默认行为,我们总可以在 Reflect 上获取到默认行为。

### Iterator
Iterator即迭代器,它是一种接口,为各种不同的数据结构提供了统一的访问机制,换句话说,只要有任何数据结构部署了迭代接口,就可以使用统一的方式的来遍历它。

实现可迭代接口的数据结构,一般都自身实现或继承了以`Symbol.iterator`属性的,就属于可迭代对象。`Symbol.iterator`属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。

一个包含`next()`方法的对象,才可以称为一个迭代对象。`next()`对象的会有返回一个对象,对象中包含两个值,如下所示:

-   `value`:迭代器返回的任何`JavaScript`值。`done`为`true`时可省略。
-   `done`:一个布尔值,为`false`时表示迭代未停止,为`true`时立即停止迭代器,且可以省略`value`的值。

JavaScript原生提供的迭代器接口如下图所示:

![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0063fb4c216246fb97cb4be39bbf2fa4~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1512&h=924&s=395701&e=png&b=ffffff)

### Generator
Generator是ES2015中提供的一种异步编程解决方案,定义Generator函数在`function`关键字和函数名中间使用`*`星号,函数内部使用`yield`关键字定义不同的状态。

示例代码如下:

```js
function* testGenerator() {
  // yield定义一个状态
  yield '一碗周'
  yield 'es新特性'
  return 'generator' // 终结Generator,后面即使有yield关键字也无效
}
const g = testGenerator() // 返回 Generator 对象,通过next()方法移动状态

g.next()
/* { value: '一碗周', done: false } */

g.next()
/* { value: 'es新特性', done: false } */

g.next()
/* { value: 'generator', done: true } */
```

## ES7(2016)
### 1. 幂指数操作符

增加了幂指数操作符来进行幂指数运算:

```js
console.log(2 ** 3)  // 8
```

x ** y 产生的结果等同于 Math.pow(x, y)

### 2. Array.prototype.includes

这个数组方法主要用来判断数组中是否包含某个元素:

```js
let num = [1, 2, 3, 4, 5]

console.log(num.includes(1))  // true
```
## ES8(2017)
### 1. 异步函数 async/await

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

```js
function timeout(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms)
    })
}

async function asyncPrint(value, ms) {
    await timeout(ms)
    console.log(value)
}

asyncPrint('Hello', 300)
```

上诉代码指定 300ms 后输出 Hello。

async 函数返回一个 Promise 对象,async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数:

```js
async function f() {
    return 'Hello'
}

f().then(v => console.log(v))  // 'Hello'
```

async 函数内部抛出错误会导致返回的 Promise 对象变成 rejected 状态,抛出的错误对象会被 catch 方法回调函数接受到:

```js
async function f() {
    throw new Error('出错了')
}

f().then(
    v => console.log(v),
    e => console.log(e)
)   // ‘Error: 出错了’
```

正常情况下,await 命令后面是一个 Promise 对象,如果不是,会被转为一个立即 resolve 的 Promise 对象。

await 命令后面的 Promise 对象如果变成 rejected 状态,则 reject 的参数会被 catch 方法的回调函数接收到。

只要一个 await 语句后面的 Promise 变成 rejected,那么整个 async 函数都会被中断执行。

注意:

-   await 命令后面的 Promise 对象的运行结果可能是 rejected,最好把 await 命令放在 try...catch 中。
-   多个 await 命令后面的异步操作如果不存在继发关系,最好让它们同时触发。
-   await 命令只能用在 async 函数中,如果用在普通函数中就会报错。

### 2. Object.values()

```js
Object.values({a: 1, b: 2, c: 3}); // [1, 2, 3]
```

### 3. Object.entries()

```js
Object.entries({a: 1, b: 2, c: 3}); // [["a", 1], ["b", 2], ["c", 3]]
```
### 4. Object.getOwnPropertyDescriptors()

### 5. String padding

```js
// padStart
'hello'.padStart(10); // "     hello"
// padEnd
'hello'.padEnd(10) "hello     "
```

### 6. 函数参数列表结尾允许逗号

### 7. Object.getOwnPropertyDescriptors()

> 获取一个对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。

### 8. SharedArrayBuffer对象

> SharedArrayBuffer 对象用来表示一个通用的,固定长度的原始二进制数据缓冲区,

```js
/**
 * 
 * @param {*} length 所创建的数组缓冲区的大小,以字节(byte)为单位。  
 * @returns {SharedArrayBuffer} 一个大小指定的新 SharedArrayBuffer 对象。其内容被初始化为 0。
 */
new SharedArrayBuffer(10)
```

### 9. Atomics对象

> Atomics 对象提供了一组静态方法用来对 SharedArrayBuffer 对象进行原子操作。
## ES9(2018)
### 1. 异步迭代

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

```js
async function process(array) {
  for await (let i of array) {
    // doSomething(i);
  }
}
```

### 2. Promise.finally()

```js
Promise.resolve().then().catch(e => e).finally();
```

### 3. Rest/Spread 属性

```js
const values = [1, 2, 3, 5, 6];
console.log( Math.max(...values) ); // 6
```

### 4. 正则表达式命名捕获组

```js
const reg = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;
const match = reg.exec('2021-02-23');
```

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4ea0cc2e73934c48916807b0c83724bb~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=470&h=232&s=56299&e=png&b=fefdfd)
### 5. 正则表达式反向断言

```
(?=p)、(?<=p)  p 前面(位置)、p 后面(位置)
(?!p)、(?<!p>) 除了 p 前面(位置)、除了 p 后面(位置)
```

`(?<=w)`


![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c312beda282d425c8b722762e1fd3b23~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=982&h=114&s=29576&e=png&b=f8f8f8)
`(?<!w)`

![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/da4ffc765d8b49b9b08dd037654aeaf3~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=976&h=125&s=31341&e=png&b=f7f7f7)
#### 6. 正则表达式dotAll模式

> 正则表达式中点.匹配除回车外的任何单字符,标记s改变这种行为,允许行终止符的出现

```js
/hello.world/.test('hello\nworld');  // false
```
![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/35eebb26f4164c63a65cb9110fd5b7c3~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=949&h=173&s=33138&e=png&b=f7f7f7)
## ES10(2019)
### 1. Array.flat()和Array.flatMap()

flat()

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

flatMap()

```js
[1, 2, 3, 4].flatMap(a => [a**2]); // [1, 4, 9, 16]
```

### 2. String.trimStart()和String.trimEnd()

去除字符串首尾空白字符

### 3. String.prototype.matchAll

> matchAll()为所有匹配的匹配对象返回一个迭代器

```js
const raw_arr = 'test1  test2  test3'.matchAll((/t(e)(st(\d?))/g));
const arr = [...raw_arr];
```

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9957c045071d4820b87f6ccc56973ec7~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=644&h=97&s=10066&e=webp&b=fcfbfb)

### 4. Symbol.prototype.description

> 只读属性,回 Symbol 对象的可选描述的字符串。

```js
Symbol('description').description; // 'description'
```

### 5. Object.fromEntries()

> 返回一个给定对象自身可枚举属性的键值对数组

```js
// 通过 Object.fromEntries, 可以将 Map 转化为 Object:
const map = new Map([ ['foo', 'bar'], ['baz', 42] ]);
console.log(Object.fromEntries(map)); // { foo: "bar", baz: 42 }
```

### 6. 可选 Catch
## ES11(2020)
### 1. Nullish coalescing Operator(空值处理)

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

```js
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'  // ''
```

### 2. Optional chaining(可选链)

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

```js
let user = {}
let u1 = user.childer.name // TypeError: Cannot read property 'name' of undefined
let u1 = user.childer?.name // undefined
```

### 3. Promise.allSettled

> 返回一个在所有给定的promise已被决议或被拒绝后决议的promise,并带有一个对象数组,每个对象表示对应的promise结果

```js
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => reject('我是失败的Promise_1'));
const promise4 = new Promise((resolve, reject) => reject('我是失败的Promise_2'));
const promiseList = [promise1,promise2,promise3, promise4]
Promise.allSettled(promiseList)
.then(values=>{
  console.log(values)
});
```

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8812d876f9514c1992273f65e7bc342d~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=649&h=125&s=8112&e=webp&b=fefdfd)

### 4. import()

按需导入

### 5. 新基本数据类型BigInt

> 任意精度的整数

### 6. globalThis

-   浏览器:window
-   worker:self
-   node:global
## ES12(2021)
### 1. replaceAll

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

```js
const str = 'hello world';
str.replaceAll('l', ''); // "heo word"
```

### 2. Promise.any

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

```js
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);
});
```

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/57aca880439f42c9bffaaeb80232629c~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=657&h=100&s=5734&e=webp&b=fcfcfc)

### 3. WeakRefs

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

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

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

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

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

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

### 5. 数字分隔符

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

```js
const money = 1_000_000_000;
//等价于
const money = 1000000000;

1_000_000_000 === 1000000000; // true
```

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dc50404a88294da29a8972b478fc723c~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=660&h=84&s=3020&e=webp&b=fdfcfc)
## ES13(2022)
### 1.class的扩展

在ES2022中允许我们并不在`constructor`中定义类的成员,示例代码如下:

```js
class C {
  myName = '一碗周'
}
/* 两者是一致的 */
class C {
  constructor() {
    myName = '一碗周'
  }
}
```

> 如果成员只声明不初始化它的默认值是undefined。

在ES2022中允许我们使用`#`开头命名的变量作为类的私有成员,示例代码如下:

```js
class C {
  #myName = '一碗周'
}
const c = new C()
console.log(#myName) //  Private field '#myName' must be declared in an enclosing class
```

### 2. await在顶层使用

在ES2022中新增了允许在顶层使用`await`,在顶层可以不适用`async`函数进行包裹,示例代码如下:

```js
import { AsyncFun } from 'module'
await AsyncFun()
console.log(123)
```

### 3. Object.hasOwn()

`Object.hasOwn()`方法用于判断某个对象上是否具有某个属性,示例代码如下:

```js
const person = {
  name: '一碗周',
  age: 18,
}
console.log(Object.hasOwn(person, 'name')) // true
console.log(Object.hasOwn(person, 'sex')) // false
```

### 4. Array.prototype.at()

ES2022中新增的`at()`方法,它的作用是获取数组中的某个成员,它的参数是数组的索引,与直接使用索引的方式不同,它允许我们传递负值,等同于从后面倒数,示例代码如下:

```js
const arr = [1, 2, 3, 4, 5, 6]
console.log(arr.at(-1)) // 6
// 等同于 arr[arr.length - 1]
```

### 5. d修饰符

正则表达式增加了一个`/d`修饰符,当使用正则表达式的`exec()`方法时,如果有`/d`修饰符,那么结果会多返回一个indices属性,用来表示匹配的结果的在原字符串中的起始index值。示例代码如下:

```js
const str = 'JavaScript'
const r = /a/d

const m = r.exec(str)
console.log(m.indices[0]) //[ 1, 2 ]
```
### 6. 顶层 await

之前await关键字只能在async函数内部使用,在外部使用就会报错: SyntaxError - SyntaxError: await is only valid in async function;

在ES13 允许在模块的顶层使用 await, 并且不再需要配合 async函数使用,它允许模块充当大型异步函数,使得我们在 ESM 模块中可以等待资源的加载,只有资源加载完毕之后才会去执行当前模块的代码。

实际运用:

a、动态加载模块

```js
const strings = await import(`/i18n/${navigator.language}`);
```

这对于开发/生产拆分、国际化、环境拆分等非常有用。

b、资源初始化

```js
const connection = await dbConnector();
```

配合try catch实现依赖回退

```
let jQuery;
try {
  jQuery = await import('https://cdn-a.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.com/jQuery');
}
```

依赖发生故障时,可以回退到旧版本,防止程序崩溃。
### 7. at()
.at()是数组新增的一个方法,通过传递给定索引来获取数组元素,这个索引可以是正数也可以是负数,当索引是正数时效果和 [] 是一样的,当索引是负数时就会从数组的最后一项开始。

```JS
const arr = [1,2,3,4,5]; 
arr[arr.length-1] // 5
const arr = [1,2,3,4,5]; 
arr.at(-1) // 5
```

支持类型

-   String
-   Array
-   Typed Array
## ES14(2023)
### 1. Array.prototype.toSorted

toSorted() 与 Array.prototype.sort() 具有相同的签名,但它创建一个新的数组,而不是对原数组进行操作。

```js
let arr = [5, 4, 2, 3, 1];
arr === arr.sort(); // true - [1, 2, 3, 4, 5]

arr === arr.toSorted(); // false - [1, 2, 3, 4, 5]
```

toSorted() 和 sort() 一样,接受一个可选参数作为比较函数。例如,我们可以使用 toSorted() 创建一个按降序排列的新数组

```js
const numbers = [10, 5, 2, 7, 3, 9, 1, 6, 4];
const sortedNumbers = numbers.toSorted((a, b) => {
  return b - a;
});
console.log(sortedNumbers); // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
```

需要注意的是,toSorted() 也可以应用于对象数组。这种情况下,需要提供一个使用对象上的数据的比较函数,因为对象没有自然的排序方式。

```js
// 比较对象
const objects = [
  { name: "John", age: 30 },
  { name: "Jane", age: 25 },
  { name: "Bill", age: 40 },
  { name: "Mary", age: 20 }
];
const sortedObjects = objects.toSorted((a, b) => {
  return a.name.localeCompare(b.name);
});
console.log(sortedObjects);
// [{"name":"Bill","age":40},{"name":"Jane","age":25},{"name":"John","age":30},{"name":"Mary","age":20}]
```

### 2. Array.prototype.toReversed

与 toSorted() 和 sort() 一样,toReversed() 是 reverse() 的复制版本。

```js

["a", "b", "c", "d", "e"].toReversed(); // ['e', 'd', 'c', 'b', 'a']
```

### 3. Array.prototype.with

新的 with() 方法允许您基于索引修改单个元素,并返回一个新的数组。因此,如果您知道索引和新值,这个方法非常方便。需要注意的是with() 是 set() 的复制伴侣。

```js

const arr4 = ["I", "am", "the", "Walrus"];

// 用 "Ape Man" 替换字符串 "Walrus"。
const newArr4 = arr4.with(3, "Ape Man");

console.log(newArr4);
```

### 4. Array.prototype.findLast

findLast() 方法允许您从数组中获取匹配元素的最后一个实例。如果找不到匹配元素,则返回 undefined。下面代码中提供了一个简单的示例,我们从数组中获取最后一个偶数。

```js

const arr = [54, 34, 55, 75, 98, 77];

const lastEvenIndex = arr.findLast((element) => {
  return element % 2 === 0;
});

console.log(lastEvenIndex); // 98
```

findLast() 还支持传递一个 "thisArg" 来设置上下文。也就是说,第二个参数将告诉第一个参数函数 this 关键字将引用什么。从下面代码中看到这一点,我们使用一个自定义对象来找到可以被 5 整除的第一个元素。

```js

const arr6 = [54, 34, 55, 75, 98, 77];
const myObject = { testCase: 5 };
const lastEvenIndex = arr5.findLast((element) => {
  return element % myObject.testCase === 0;
}, myObject);

console.log(lastEvenIndex); // 75
```

### 5.Array.prototype.findLastIndex

findLastIndex() 的工作方式与 findLast() 相同,只是它返回匹配元素的索引而不是元素本身。例如,下面例子展示如何找到最后一个可以被 6 整除的元素的索引。

```
代码清单 8. 使用 findLastIndex() 找到元素的索引

const arr = [54, 34, 55, 75, 98, 77];
arr.findLastIndex(x => x % 6 === 0); // 0
```

### 6.Array.prototype.toSpliced

上面新增的所有方法也适用于 TypedArray,但 toSpliced() 这个新的数组方法只存在于 Array 中。toSpliced() 方法是 splice() 的复制版本,splice()是js中数组操作常用的方法;

假设我们有一个颜色数组,需要在中间插入一些新的颜色(粉红色和青色)。这会创建一个新数组,而不是修改原始数组。

```js

const arr = ["red", "orange", "yellow", "green", "blue", "purple"];
const newArr = arr.toSpliced(2, 1, "pink", "cyan");
console.log(newArr);
// ["red", "orange", "pink", "cyan", "green", "blue", "purple"]
console.log(newArr[3]);
// 'cyan'
console.log(arr[3]);
// 'green'
```

### 7.正式的 shebang 支持

Shebang 是旧式 Unix 术语,表示井号后跟一个感叹号:#!(其中 "bang" 是感叹号的俚语)。

```js
#!/bin/bash

echo "Hello, world!"
```

您可以使用 ./hello.sh 直接运行上面代码。

您也可以在 JavaScript 中执行类似操作,如代码清单 11 所示。

```js
#!/usr/bin/env node

console.log("Hello, world!");
```

上面例子告诉操作系统使用 node 程序来运行此脚本。只需键入 ./hello.js 即可运行它。如果没有 #!是无法运行的。

Shebang 支持是规范中已经实现并在多种情境下非正式采用的特性之一。

### 8.Symbol 作为 WeakMap 的键

ES14中的最后一个新功能是Symbol 可以作为 WeakMap 的键使用。在这之前,WeakMap仅允许对象作为键值,新特性更容易创建和共享key。

```
var map = new WeakMap(); // 创建一个弱映射
function useSymbol(symbol){
    doSomethingWith(symbol);
    var called = map.get(symbol) || 0
```

上面的例子允许从外部调用者调用计数器,并在不再有引用时释放映射条目。代码本身无法知道何时不再需要引用,如果使用普通的 Map,将会导致内存泄漏。这是因为即使在调用它的客户端不再需要引用时,代码仍然会保留对该引用的持有。在这种情况下使用 WeakMap,可以确保垃圾回收在不再存在对键符号的引用时删除映射条目。
### 9. Record 和 Tuple 类型:
```js
const person = {
  name: "John Doe",
  age: 30,
  hobbies: ["coding", "reading", "playing guitar"]
};
```

这段代码定义了一个名为 person 的 Record,其中包含三个元素:姓名、年龄和爱好。name 元素是一个字符串,age 元素是一个整数,hobbies 元素是一个字符串数组。

以下是 ES14 之后的 ECMAScript 2023 中的元组示例:

```js
const colors = ["red", "green", "blue", "purple"];
```

此代码定义了一个名为颜色的元组,其中包含四个元素:红色、绿色、蓝色和紫色。元组的元素现在可以是任何类型的数据。
# 参考:
[JS语法 ES6、ES7、ES8、ES9、ES10、ES11、ES12新特性](https://juejin.cn/post/6932741345467432967)

[ES14新特性揭秘,对前端开发有哪些影响?](https://www.cnblogs.com/dawnyu/p/17709396.html)


 

这篇关于Javascript[ECMAScript] ES6、ES7、ES8、ES9、ES10、ES11、ES12、ES13、ES14[2023]新特性的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/745102

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️