22

一、es7 新特性

1、Array.prototype.includes() 方法

该方法可以返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。

[1,2,3].includes(4) // false
['ss', 'aa'].includes('aa') // true

该方法接受2个参数,第二个参数表示搜索的起始位置,默认为0。如果参数为负数,则表示倒数。

[1, 2, 3].includes(3, 3) // false
[1, 2, 3].includes(3, -1) // true 

我们通常使用indexOf来检查是否包含某个元素,但是会有缺点:一是不够直观,要和-1去比较;二是它内部使用严格相等(===)来判断,导致会对NaN的误判。

[NaN].indexOf(NaN) // -1
[NaN].includes(NaN) // true
浏览器支持情况

目前只有IE不支持。

浏览器支持情况

2、求幂运算符**

**具有与Math.pow()同样的计算效果。

console.log(2**10) // 1024
console.log(Math.pow(2, 10)) // 1024
浏览器支持情况

目前只有IE浏览器不支持。

浏览器支持情况

二、es8 新特性

1、async/await异步解决方案

提出场景:JS 是单线程、优化回调地狱的写法。

es6为了解决回调的方式,提出了promisethen函数,但是当业务逻辑过多时,需要多个then函数,此时语义上不是很清晰。

new Promise( (resolve, reject) =>  {
  this.login(resolve)
}).then(() => this.getInfo())
  .then(() => {// do something})
  .catch(() => { console.log("Error") })

基于上述,引入了async/await,提供了在不阻塞主线程的情况下使用同步代码来实现异步访问资源的能力,其中await不可以脱离async单独使用,且await后面一定是Promise对象,如果不是会自动包装成Promise对象。

async function getInfo() {
  const result1 = await this.login()
  const result2 = await this.getInfo()
}

async可以单独使用,且返回的是一个Promise对象,且其内部return语句的返回值,会成为then方法回调函数的参数。

async function f() {
  return 'hello world';
}

f().then(val => console.log(val)) // hello world

具体关于async的用法,可参考 es6.ruanyifeng.com/#docs/async

浏览器支持情况

浏览器支持情况

2、Object.values()/Object.entries()方法

Object.values()方法会返回一个数组,其数组成员是参数对象自身可枚举属性的键值。

注意:当属性值是数值时,会按照数值大小 从小到大遍历。
const obj1 = { foo: 'bar', baz: 42 }
Object.values(obj1) // ["bar", 42]

const obj2 = { 100: 'a', 1: 'b', 2: 'c' }
Object.values(obj2) // ["b", "c", "a"]

Object.entries()方法返回一个数组,数组成员是参数对象自身可枚举属性的键值对数组。

const obj1 = { foo: 'bar', baz: 42 }
Object.entries(obj1) // [ ["foo, "bar"], ["baz", 42] ]

const obj2 = { 100: 'a', 1: 'b', 2: 'c' }
Object.entries(obj2) // [ ["1", "b"], ["2", "c"], ["100", "a"] ]
浏览器支持情况

目前只有IE浏览器不支持。

浏览器支持情况

3、字符串填充padStart()/padEnd()方法

用于字符串补全长度的功能,如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。

padStart()/padEnd()方法接收2个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。

'x'.padStart(5, 'ab') // 'ababx'
'x'.padEnd(5, 'ab') // 'xabab'

'xxx'.padStart(2, 'ab') // 'xxx'

如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串。

'abc'.padStart(8, 'xxx') // 'xxxxxabc'
浏览器支持情况

目前只有IE浏览器不支持。

浏览器支持情况

4、Object.getOwnPropertyDescriptors()

提出场景:为了解决Object.assign()无法正确拷贝get属性和set属性的问题。
Object.assign方法总是拷贝一个属性的值,而不会拷贝它背后的赋值方法或取值方法。

ES5 的Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor),而Object.getOwnPropertyDescriptors()方法,返回指定对象所有自身属性(非继承属性)的描述对象。

const obj = {
  foo: 123,
  get bar() { return 'abc' }
};

Object.getOwnPropertyDescriptors(obj)
Object.getOwnPropertyDescriptor(obj, foo)

使用Object.assign()进行拷贝

const source = {
  set foo(value) {
    console.log(value);
  }
};

const target1 = {};
Object.assign(target1, source);
Object.getOwnPropertyDescriptor(target1, 'foo')

上述将 source对象拷贝给target1对象,获取属性值时得到了undefined,是因为Object.assign()方法总是拷贝一个属性的值,而不会拷贝它背后的赋值方法或取值方法

此时可以使用Object.definePropertiesObject.getOwnPropertyDescriptors配合使用实现拷贝。

const source = {
  set foo(value) {
    console.log(value);
  },
  arr: [1, 2, 3]
};

const target2 = {};
Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
Object.getOwnPropertyDescriptor(target2, 'foo')

source.arr.push(4)
console.log(source)
console.log(target2)
注意:实现的是浅拷贝
具体应用方式可参考 https://es6.ruanyifeng.com/#Object-getOwnPropertyDescriptors
浏览器支持情况

目前只有IE不支持

浏览器支持情况

三、es9 新特性

1、Promise.prototype.finally()

finally()方法返回一个Promise, 在Promise执行结束时,无论结果是fulfilled或者是rejected,都会执行finally指定的回调函数。

let p = new Promise((resolve, reject) => {
    resolve()
})

p.then(() => 
    console.log(1) // 1
).catch((err) => {
    console.log(err)
}).finally(() => {
    console.log('finally') // 'finally'
})
浏览器支持情况

目前只有IE 不支持。

浏览器支持

2、对象扩展运算符...

与数组类似,引入了对象扩展运算符,可以将一个对象的属性拷贝到另一个对象上,实现的是浅拷贝。

let form = {
    age: 11,
    name: 'John'
}

let params = {
    ...form,
    profession: 'student'
}
3、for await ... of

for ... of 循环用来遍历同步的迭代器接口,而for await ... of是异步迭代器,会等待前一个成员的状态改变后才会遍历到下一个成员,相当于async函数内部的await

function getTime (time) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve(time)
    }, time)
  })
}
async function test () {
  let arr = [getTime(2000), getTime(100), getTime(3000)]
  for await (let item of arr) {
    console.log(Date.now(), item)
  }
}
test()
// 1598251267580 2000
// 1598251267580 100
// 1598251268583 3000
浏览器支持情况

Edge 不支持。

浏览器支持

四、es10 新特性

1、Array.prototype.flat()

Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。

flat()方法默认会“拉平”一层,可以传入整数作为参数,表示想要拉平的层数,默认是1。

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

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

当对嵌套多层的数组想要转成一维数组,可以传入关键字Infinity

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

如果原数组有空位,flat()会跳过空位。

[1, , 2, , 3, 4].flat() // [1, 2, 3, 4]
浏览器支持情况

目前只有IE 和 Edge不支持。

浏览器支持情况

2、Array.prototype.flatMap()

flatMap()方法对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。

let arr = [1, 2, 3]
console.log(arr.map(item => [item * 2]).flat()) // [2, 4, 6]
console.log(arr.flatMap(item => [item * 2])) // [2, 4, 6]

实际上flatMap是综合了mapflat的操作,所以它也只能打平一层

[1, 2, 3, 4].flatMap(x => [x * 2]) // [2, 4, 6, 8]

[1, 2, 3, 4].flatMap(x => [[x * 2]]) // [[2], [4], [6], [8]]
浏览器支持情况

目前只有IE 和 Edge不支持。

浏览器支持情况

3、Object.fromEntries()

Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。

const entries = new Map([
    ['age', 10],
    ['name', 'Amy']
])

Object.fromEntries(entries) // { age: 10, name: 'Amy' }
浏览器支持情况

目前只有IE、Edge、Opera for Android、Samsung Internet不支持。

浏览器支持情况

4、String.trimStart()/String.timeEnd()

这两个方法的行为与trim()一致,trimStart()消除字符串头部的空格,trimEnd()消除字符串尾部的空格,且不会改变原始字符串。

const str = '   lalallal  '
str.trim()       // 'lalallal'
str.trimStart()  // 'lalallal  '
str.trimEnd()    // '   lalallal'
浏览器支持情况

目前只有IE不支持。

浏览器支持情况

5、try...catch

catch中的参数变成一个可选项。

try {
 console.log(1)
} catch {
 console.log(2)
}
浏览器支持情况

浏览器支持情况

6、Function.prototype.toString()

修改后的toString()方法,会返回和原函数一模一样的原始代码。

function /* foo comment */ foo () {}

foo.toString() // "function /* foo comment */ foo () {}"
浏览器支持情况

image

7、Symbol.prototype.description

我们在创建Symbol时,可以添加一个描述。

读取时要显示转为字符串通过toString()方法才可以读取。

const sym = Symbol('foo');

String(sym) // "Symbol(foo)"
sym.toString() // "Symbol(foo)"

description属性,可以直接方便的返回Symbol的描述。

const sym = Symbol('foo');

sym.description // "foo"
浏览器支持情况

只有Edge、IE 不支持。

浏览器支持

五、es11 新特性

一、ES2020

1、可选链操作符?.
let title = data && data.result && data.result.title

// 之后
let title = data?.result?.title

如果data 或者 data.result是null/undefined,表达式将会短路计算直接返回undefined。

浏览器支持情况

目前只有Chrome 79 及 Opera 65及以上版本支持。
image

2、空位合并操作符 ??
// 之前
'' || 'default value' // 'default value'
0 || 'default value' // 'default value'

// 之后
'' ?? 'default value' // ''

??左侧只有是undefinednull时,才返回右侧默认值,否则都为左侧的值。

let c = a ?? b
// 等价于
let c = a !== undefined && a !== null ? a : b
浏览器支持情况

目前只有Chrome 80 及 Firefox 72及以上版本支持。
image

3、BigInt 任意精度整数

js 只能安全的标识-(2^53-1)至 2^53-1范围的值,超出这个范围的整数计算会丢失精度。

var num = Number.MAX_SAFE_INTEGER // 9007199254740991

var num1 = num + 1 // 9007199254740992
var num2 = num + 2 // 9007199254740992


9007199254740992 === 9007199254740993 // true

于是产生了BigInt它是第七个原始类型,可以进行大数整数运算,使用时需要再数字后面加上n,或者使用BigInt()方法进行转化。

var a = 111
var big = BigInt(a)

big === 111n //true
typeof big === 'bigint' // true
typeof 111n // bigint

1222223456789098765n +2n // 1222223456789098767n
浏览器支持情况

目前只有Chrome 67 及 Firefox 68及以上版本支持。
image

4、import() 动态加载

返回一个Promise 对象,且当加载模块成功以后,这个模块会作为一个对象,当作then方法的参数。

const modulePage = 'page.js'; 

import(modulePage)
     .then((module) => {
        module.default();
     });

这种方式也支持 await关键字。

(async () => {
  const helpersModule = 'helpers.js';
  const module = await import(helpersModule)
  const total = module.sum(2, 2);
})();
浏览器支持情况

目前除了IE和edge不支持,Chrome 是63及以上版本支持。
image

5、globalThis

用于获取全局this
在浏览器中是window,在 web workers中是self,在node中是global

// 之前
const getGlobal = function(){
  if(typeof self !== 'undefined') return self
  if(typeof window !== 'undefined') return window
  if(typeof global !== 'undefined') return global
  throw new Error('unable to locate global object')
}

globalThis目的就是提供一标准化访问全局对象,而不需要考虑不同的环境问题。

// worker.js
globalThis === self

// node.js
globalThis === global

// browser.js
globalThis === window
浏览器支持情况

目前除了IE、Opera和edge不支持,Chrome 是71及以上版本支持。
image

6、Promise.allSettled

Promise.all具有并发执行异步任务的能力,但是最大问题是如果参数中有一个为reject,则整个Promise.all会立即终止,并返回一个reject的新的Promise对象。


const promises = [
 Promise.resolve(1),
 Promise.resolve(2),
 Promise.reject('error')
];
 
 
Promise.all(promises)
 .then(responses => console.log(responses))

通常我们可能会用 Promsie.all 来并发请求三个接口,如果一个接口reject了,则会导致三个接口数据全都无法展示,而Promise.allSettled的出现就可以解决这个痛点。

Promise.allSettled接受一个Promise 的数组,并返回一个新的数组,与Promise.all不同的是,它不会进行短路,而是可以拿到每一个Promise的状态。


Promise.allSettled([
  Promise.reject({ code: 500, msg: '服务异常' }),
  Promise.resolve({ code: 200, list: [] }),
  Promise.resolve({ code: 200, list: [] })
]).then(res => {
  console.log(res)
  /*
        0: {status: "rejected", reason: {…}}
        1: {status: "fulfilled", value: {…}}
        2: {status: "fulfilled", value: {…}}
    */
  // 过滤掉 rejected 状态,尽可能多的保证页面区域数据渲染
    res.filter(el => {
      return el.status !== 'rejected'
    })
})
浏览器支持情况

目前除了IE、Opera和edge不支持,Chrome 是76及以上版本支持。
image

7、String.prototype.matchAll

String.prototypematch()方法仅返回完整的匹配结果,而不会返回正则表达式组的信息。

matchAll方法返回比match更多的信息,会包含全部的正则模式捕获结果,而无需用修饰符/g

// match方法
const text = "From 2019.01.29 to 2019.01.30";
const regexp = /(?<year>\d{4}).(?<month>\d{2}).(?<day>\d{2})/gu;
const results = text.match(regexp);
console.log(results);
// [ '2019.01.29', '2019.01.30' ]
// matchAll 方法
const text = "From 2019.01.29 to 2019.01.30";
const regexp = /(?<year>\d{4}).(?<month>\d{2}).(?<day>\d{2})/gu;
const results = Array.from(text.matchAll(regexp));
console.log(results);
// [
//   [
//     '2019.01.29',
//     '2019',
//     '01',
//     '29',
//     index: 5,
//     input: 'From 2019.01.29 to 2019.01.30',
//     groups: [Object: null prototype] { year: '2019', month: '01', day: '29' }
//   ],
//   [
//     '2019.01.30',
//     '2019',
//     '01',
//     '30',
//     index: 19,
//     input: 'From 2019.01.29 to 2019.01.30',
//     groups: [Object: null prototype] { year: '2019', month: '01', day: '30' }
//   ]
// ]
浏览器支持情况

IE、Safari、Edge不支持。

浏览器支持情况

TC39 Proposals


__青春的Smile
185 声望8 粉丝