ES7-ES12新特性

ES7

1.Array.prototype.includes()
includes()作用,是查找一个值在不在数组里,若是存在则返回true,不存在返回false.

[1,2,3,4].includes(4) // true
  • 只能判断简单类型的数据,对于复杂类型的数据,比如对象类型的数组,二维数组,这些,是无法判断的.

  • 对于NaN的处理结果不同(js中 NaN === NaN 的结果是false,indexOf()也是这样处理的,但是includes()不是这样的。)

[1,2,NaN].indexOf(NaN) // -1
[1,2,NaN].includes(NaN) // true
NaN === NaN // false

2.求幂运算符

2**3 //8
var a = 3; a**=2; // a === 9

ES8

1. async await
异步函数存在以下四种使用形式:

  • 函数声明: async function foo() {}
  • 函数表达式: const foo = async function() {}
  • 对象的方式: let obj = { async foo() {} }
  • 箭头函数: const foo = async () => {}

async用于定义一个异步函数,该函数返回一个Promise。
如果async函数返回的是一个同步的值,这个值将被包装成一个理解resolve的Promise,等同于return Promise.resolve(value)。
await用于一个异步操作之前,表示要“等待”这个异步操作的返回值。await也可以用于一个同步的值。

function 摇色子(){
    return new Promise((resolve, reject)=>{
        let sino = parseInt(Math.random() * 6 +1)
        setTimeout(()=>{
            resolve(sino)
        },3000)
    })
}
async function test(){
    let n =await 摇色子()
    console.log(n)
}
test()

2. Object.entries()
作用:将一个对象中可枚举属性的键名和键值按照二维数组的方式返回。
若对象是数组,则会将数组的下标作为键值返回。

Object.entries({ one: 1, two: 2 })    //[['one', 1], ['two', 2]]
Object.entries([1, 2])                //[['0', 1], ['1', 2]]

要点
2.1 若是键名是Symbol,编译时会被自动忽略

Object.entries({[Symbol()]:1, two: 2})  //[['two', 2]]

2.2 entries()返回的数组顺序和for循环一样,即如果对象的key值是数字,则返回值会对key值进行排序,返回的是排序后的结果

Object.entries({ 3: 'a', 4: 'b', 1: 'c' })    //[['1', 'c'], ['3', 'a'], ['4', 'b']]

2.3利用Object.entries()创建一个真正的Map

    var obj = { foo: 'bar', baz: 42 };
    
    var map1 = new Map([['foo', 'bar'], ['baz', 42]]); //原本的创建方式
    var map2 = new Map(Object.entries(obj));    //等同于map1

    console.log(map1);// Map { foo: "bar", baz: 42 }
    console.log(map2);// Map { foo: "bar", baz: 42 }

3.Object.values()
只返回自己的键值对中属性的值。它返回的数组顺序,也跟Object.entries()保持一致

Object.values({ one: 1, two: 2 })            //[1, 2]
Object.values({ 3: 'a', 4: 'b', 1: 'c' })    //['c', 'a', 'b']

4. 字符串填充
字符串填充padStart()和padEnd()

用法
String.padStart(targetLength, padding)
参数:字符串目标长度和填充字段

'Vue'.padStart(10)           //'       Vue'
'React'.padStart(10)         //'     React'
'JavaScript'.padStart(10)    //'JavaScript'

'Vue'.padEnd(10, '_*')           //'Vue_*_*_*_'
'React'.padEnd(10, 'Hello')      //'ReactHello'
'JavaScript'.padEnd(10, 'Hi')    //'JavaScript'
'JavaScript'.padEnd(8, 'Hi')     //'JavaScript'

5.Object.getOwnPropertyDescriptors()
该方法会返回目标对象中所有属性的属性描述符,该属性必须是对象自己定义的,不能是从原型链继承来的
如果没有任何自身属性,则返回空对象。

    var obj = {
        id:  1,
        name: '霖呆呆',
        get gender() {
            console.log('gender')
        },
        set grad(d) {
            console.log(d)
        }
    }
    console.log(Object.getOwnPropertyDescriptors(obj))
 //输出   
{
  gender: {
    configurable: true,
    enumerable: true,
    get: f gender(),
    set: undefined
  },
  grade: {
    configurable: true,
    enumerable: true,
    get: undefined,
    set: f grade(g)
  },
  id: {
    configurable: true,
    enumerable: true,
    value: 1,
    writable: true
  },
  name: {
    configurable: true,
    enumerable: true,
    value: '霖呆呆',
    writable: true
  }
}

getOwnPropertyDescriptor()比较

var obj = {
    id: 1,
    name: '霖呆呆',
    get gender() {
        console.log('gender')
    },
    set grad(d) {
        console.log(d)
    }
}
console.log(Object.getOwnPropertyDescriptor(obj, 'id'))
        
//输出结果
 {
  id: {
    configurable: true,
    enumerable: true,
    value: 1,
    writable: true
  }
}

两者的区别:一个是只返回知道属性名的描述对象,一个返回目标对象所有自身属性的描述对象

7. ShareArrayBuffer

ShareArrayBuffer对象用来表示一个泛型的,固定长度的原生二进制数据缓冲区,类似于ArrayBuffer对象。但在某种程度上,它们能被用于在共享内存上创建视图。与ArrayBuffer不同的是,ShareArrayBuffer不能被移除。

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

8.Atomics对象

Atomics 对象提供了一组静态方法用来对 SharedArrayBuffer 对象进行原子操作。

这些原子操作属于 Atomics 模块。与一般的全局对象不同,Atomics 不是构造函数,因此不能使用 new 操作符调用,也不能将其当作函数直接调用。Atomics 的所有属性和方法都是静态的(与 Math 对象一样)。

多个共享内存的线程能够同时读写同一位置上的数据。原子操作会确保正在读或写的数据的值是符合预期的,即下一个原子操作一定会在上一个原子操作结束后才会开始,其操作过程不会中断。

  • Atomics.add()静态方法会将给定的值加到数组里的某个特定位置上,并返回该位置的旧值。此原子操作保证在写上修改的值之前不会发生其他写操作。
    语法: Atomics.add(typedArray, index, value)

  • Atomics.load() 静态方法 Atomics.load() 返回一个数组当中给定位置的值。
    语法: Atomics.load(typedArray, index)

  • Atomics.and()静态方法会将给定的值与数组上的值进行按位与操作,并将结果赋值给数组,然后返回数组该位置上的旧值。此原子操作保证在写上修改的值之前不会发生其他写操作。
    语法: Atomics.and(typedArray, index, value)

  • Atomics.or()方法计算数组中给定位置的按位或给定值, 并返回该位置的旧值。此原子操作保证在修改后的值被写回之前不会发生其他写入。
    语法:Atomics.or(typedArray, index, value)

  • Atomics.compareExchange()静态方法会在数组的值与期望值相等的时候,将给定的替换值替换掉数组上的值,然后返回旧值。此原子操作保证在写上修改的值之前不会发生其他写操作。
    语法: Atomics.compareExchange(typedArray, index, expectedValue, replacementValue)

  • Atomics.exchange() 静态方法会用 给定的值替换掉数组上的值,然后返回数组的旧值。此原子操作保证在写上修改的值之前不会发生其他写操作。
    语法: Atomics.exchange(typedArray, index, value)

  • 静态的Atomics.store()方法将给定的值存储在数组中的指定位置,并返回该值。
    语法: Atomics.store(typedArray, index, value)

  • 静态方法Atomics.sub() 减去数组中给定位置的给定值,并在该位置返回旧值。这种原子操作保证了只有修改后的值被写回,才能进行其他的写操作。
    语法:Atomics.sub(typedArray, index, value)

  • Atomics.wake()方法唤醒在等待队列中休眠的某些代理
    语法:Atomics.wake(typedArray, index, count)

ES9

1.异步迭代
ES2018引入异步迭代器(asynchronous iterators),这就像常规迭代器,除了next()方法返回一个Promise。因此await可以和for...of循环一起使用,以串行的方式运行异步操作。例如

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

2. Promise.finally()
一个Promise调用链要么成功到达最后一个.then(),要么失败触发.catch()。在某些情况下,你想要在无论Promise运行成功还是失败,运行相同的代码

function doSomething() {
  doSomething1()
  .then(doSomething2)
  .then(doSomething3)
  .catch(err => {
    console.log(err);
  })
  .finally(() => {
    // finish here!
  });
}

3.Rest/Spread 属性
ES2015引入了Rest参数和扩展运算符。三个点(...)仅用于数组

ES2018为对象解构提供了和数组一样的Rest参数()和展开操作符

const myObject = {
  a: 1,
  b: 2,
  c: 3
};

const { a, ...x } = myObject;
// a = 1
// x = { b: 2, c: 3 }

你可以使用它给函数传递参数:

restParam({
  a: 1,
  b: 2,
  c: 3
});

function restParam({ a, ...x }) {
  // a = 1
  // x = { b: 2, c: 3 }
}

4.正则表达式命名捕获组
JavaScript正则表达式可以返回一个匹配的对象——一个包含匹配字符串的类数组,例如:以YYYY-MM-DD的格式解析日期:

const
  reDate = /([0-9]{4})-([0-9]{2})-([0-9]{2})/,
  match  = reDate.exec('2018-04-30'),
  year   = match[1], // 2018
  month  = match[2], // 04
  day    = match[3]; // 30

这样的代码很难读懂,并且改变正则表达式的结构有可能改变匹配对象的索引。
ES2018允许命名捕获组使用符号?,在打开捕获括号(后立即命名,示例如下:

const
  reDate = /(?[0-9]{4})-(?[0-9]{2})-(?[0-9]{2})/,
  match  = reDate.exec('2018-04-30'),
  year   = match.groups.year,  // 2018
  month  = match.groups.month, // 04
  day    = match.groups.day;   // 30

任何匹配失败的命名组都将返回undefined
命名捕获也可以使用在replace()方法中。例如将日期转换为美国的 MM-DD-YYYY 格式:

const
  reDate = /(?[0-9]{4})-(?[0-9]{2})-(?[0-9]{2})/,
  d      = '2018-04-30',
  usDate = d.replace(reDate, '$-$-$');

5. 正则表达式反向断言
js使用正则,对前瞻断言和后瞻断言的理解(转发)
目前JavaScript在正则表达式中支持先行断言(lookahead)。这意味着匹配会发生,但不会有任何捕获,并且断言没有包含在整个匹配字段中。例如从价格中捕获货币符号

const
  reLookahead = /\D(?=\d+)/,
  match       = reLookahead.exec('$123.89');

console.log( match[0] ); // $

ES2018引入以相同方式工作但是匹配前面的反向断言(lookbehind),这样我就可以忽略货币符号,单纯的捕获价格的数字:

const
  reLookbehind = /(?<=\D)\d+/,
  match        = reLookbehind.exec('$123.89');

console.log( match[0] ); // 123.89

断言写法
前瞻断言
(?=exp) 顺序肯定环视,表示所在位置右侧能够匹配exp
(?!exp) 顺序否定环视,表示所在位置右侧不能匹配exp

后瞻断言
(?<=exp) 逆序肯定环视,表示所在位置左侧能够匹配exp
(?

6. 正则表达式dotAll模式
正则表达式中点.匹配除回车外的任何单字符,标记s改变这种行为,允许行终止符的出现,例如:(我的理解是有正则 /./s.就可以代表任一单字符了)

/hello.world/.test('hello\nworld');  // false
/hello.world/s.test('hello\nworld'); // true

ES10

1.String.prototype.trimStart() / String.prototype.trimEnd()
ES5来,String.prototype.trim()被用于去除头尾上的空格、换行符等,现在通过trimStart(),trimEnd()来头和尾进行单独控制

const string = ' Hello ES2019! ';
string.trimStart();
// 'Hello ES2019! '
string.trimEnd();
// ' Hello ES2019!'

2. Object.fromEntries()
ES8为我们引入了Object.entries把一个对象转为[key, value]键值对的形式,可以运用于像 Map 这种结构中。凡事有来有回,Object.fromEntries()用于把键值对还原成对象结构。

const entries = [ ['foo', 'bar'] ];
const object = Object.fromEntries(entries);
// { foo: 'bar' }

3.Array.prototype.flat() / Array.prototype.flatMap()
把数组展平是Array原型给我们带来的新特性,通过传入层级深度参数(默认为1),来为下层数组提升层级。如果想提升所有层级可以写一个比较大的数字甚至是Infinity

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

Array.prototype.flatMap()它是Array.prototype.map()Array.prototype.flat()的组合,通过对map调整后的数据尝试展平操作。

[1, 2, [3, 4]].flatMap(v => {
  if (typeof v === 'number') {
    return v * 2
  } else {
    return v.map(v => v * 2)
  }
})
// [2, 4, 6, 8]

4. catch 的参数改为可选
在进行try...catch错误处理过程中,不用必须catch传参数,省略catch绑定的参数和括号

const isValidJSON = json => {
  try {
    JSON.parse(json);
    return true;
  } catch {
    return false;
  }
};

5.Symbol.description
Symbol是ES6中引入的基本数据类型,可以用作对象属性的标识符。描述属性是只读的,可用于获取符号对象的描述,更好了解它的作用。

const symbol = Symbol('666我是描述');
symbol;
// Symbol(666我是描述)
Symbol.description;
// '666我是描述'

6.JSON Superset 超集
之前如果JSON字符串中包含有行分隔符(\u2028) 和段落分隔符(\u2029),那么在解析过程中会报错。

JSON.parse('"\u2028"');
// SyntaxError

现在ES2019对它们提供了支持。

JSON.parse('"\u2028"');
// ''

7.JSON.stringify() 加强格式转化

''.length;
// 2

JavaScript将emoji解释为两个字符的原因是UTF-16将emojis(以及其他不寻常的字符)表示为两个代理项的组合。我们的emoji用字符'\uD83D'和'\uDE0E'编码。但是如果试图单独编写这样一个字符,例如'\uD83D',则会认为这是一个无效的文本字符串。在早期版本中,这些字符将替换为特殊字符:

JSON.stringify('\uD83D');
// '"�"'

现在在字符代码之前插入转义字符,结果仍是可读且有效的UTF-8/UTF-16代码:

JSON.stringify('\uD83D');
// '"\\ud83d"'

8.Array.prototype.sort() 更加稳定
V8 之前的实现对包含10个以上项的数组使用了一种不稳定的快速排序算法。

一个稳定的排序算法是当两个键值相等的对象在排序后的输出中出现的顺序与在未排序的输入中出现的顺序相同时。

ES10 提供了一个稳定的数组排序:

var fruit = [
    { name: "Apple",      count: 13, },
    { name: "Pear",       count: 12, },
    { name: "Banana",     count: 12, },
    { name: "Strawberry", count: 11, },
    { name: "Cherry",     count: 11, },
    { name: "Blackberry", count: 10, },
    { name: "Pineapple",  count: 10, }
];
// 创建排序函数:
let my_sort = (a, b) => a.count - b.count;
// 执行稳定的ES10排序:
let sorted = fruit.sort(my_sort);
console.log(sorted);

**9.Function.prototype.toString() **
函数是对象,并且每个对象都有一个 .toString() 方法,因为它最初存在于Object.prototype.toString() 上。 所有对象(包括函数)都是通过基于原型的类继承从它继承的。

这意味着我们以前已经有 funcion.toString()方法了。

从ES2019开始,Function.prototype.toString()将从头到尾返回源代码中的实际文本片段。这意味着还将返回注释、空格和语法详细信息。

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

之前,Function.prototype.toString()只会返回了函数的主体,但没有注释和空格。

foo.toString();
// 'function foo() {}'

但现在,函数返回的结果与编写的一致。

foo.toString();
// 'function /* a comment  */ foo () {}'

ES11

1.String.prototype.matchAll
String.prototype的match() 方法仅返回完整的匹配结果,却不会返回特定正则表达式组(Regex groups)的信息

const text = "From 2019.01.29 to 2019.01.30";
const regexp = /(?\d{4}).(?\d{2}).(?\d{2})/gu;
const results = text.match(regexp);
console.log(results);
// [ '2019.01.29', '2019.01.30' ]

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

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

2.import()
ECMAScript 2015 引入了静态模块
ES2020提案引入import()函数,支持动态加载模块

import()函数返回一个Promise对象,加载模块成功以后,这个模块会作为一个对象,当作then回调的参数。因此,可以使用对象解构赋值的语法,获取输出接口。

import(`./home.js`)  // home.js中export const export1 = ''; ....
  .then(({export1, export2})=> 
    // 加载成功的回调
  })
  .catch(err => {
    // 加载失败的回调
  });

import()是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,import()函数与所加载的模块没有静态连接关系,这点也是与import语句不相同。import()类似于Node的require方法,区别主要是前者是异步加载,后者是同步加载。

3. BigInt – 任意精度整数
JavaScript 所有数字都保存成 64 位浮点数,这给数值的表示带来了两大限制。

  1. 数值的精度:只能到 53 个二进制位(相当于 16 个十进制位),大于这个范围的整数,JavaScript 是无法精确表示的。
  2. 大于或等于2的1024次方的数值,JavaScript 无法表示,会返回Infinity。

为了更精确地表示没有位数限制的整数,ES2020引入了不同于Number数字类型的BigInt数字类型, 只用来表示整数(大整数),没有位数的限制,任何位数的整数都可以精确表示。为了与 Number 类型区别,BigInt 类型的数据必须添加后缀n。

const a = 2172141653n;
const b = 15346349309n;

// BigInt 可以保持精度
a * b // 33334444555566667777n

// 普通整数无法保持精度
Number(a) * Number(b) // 33334444555566670000

4.Promise.allSettled
用在处理所有的 promise 都 settled 的情况,无论结果是 fulfilled 还是 rejected. 你看 ,无需 catch!

Promise.allSettled([
  fetch("https://api.github.com/users/pawelgrzybek").then(data => data.json()),
  fetch("https://api.github.com/users/danjordan").then(data => data.json())
])
  .then(result => console.log(`All profile settled`));

5. globalThis
种在不同环境中获取顶层对象的通用方式

  • 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。
  • 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。
  • Node 里面,顶层对象是global,但其他环境都不支持

6.可选链(Optional chaining)
?.用户检测不确定的中间节点(对于对象属性的长链式访问易出错又不易读), TypeScript 3.7 版本早已实现了此功能

// 之前
const title = data && data.article && data.article.title
// 之后
const title = data?.article?.title

7.空值合并运算符
|| 相比,空值合并运算符 ?? 只会在左边的值严格等于 nullundefined 时起作用。

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

8.export * as ns from “mod”
这是对 ES 规范的有力补充,它允许开发者以新名称导出另一模块的命名空间外部对象。

export * as ns from "mod"

ES12

1.replaceAll
replaceAll则是返回一个全新的字符串,所有符合匹配规则的字符都将被替换掉,替换规则可以是字符串或者正则表达式。

let string = 'I like 前端,I like 前端公虾米'

//使用replace
let replaceStr = string.replace('like','love')
console.log(replaceStr)  // 'I love 前端,I like前端公虾米'

//replace使用正则匹配所有
console.log(string.replace(/like/g,'love')) // 'I love 前端,I love 前端公虾米'

//使用replaceAll
let replaceAllStr = string.replaceAll('like','love')
console.log(replaceAllStr) // 'I love 前端,I love 前端公虾米'

需要注意的是,replaceAll在使用正则表达式的时候,如果非全局匹配(/g),则replaceAll()会抛出一个异常

let string = 'I like 前端,I like 前端公虾米'
console.log(string.replaceAll(/like/,'love')) //TypeError

2.Promise.any
当Promise列表中的任意一个promise成功resolve则返回第一个resolve的结果状态
如果所有的promise均reject,则抛出异常表示所有请求失败

Promise.any([
  new Promise((resolve, reject) => setTimeout(reject, 500, '哎呀,我被拒绝了')),
  new Promise((resolve, reject) => setTimeout(resolve, 1000, '哎呀,她接受我了')),
  new Promise((resolve, reject) => setTimeout(resolve, 2000, '哎呀,她也接受我了')),
])
.then(value => console.log(`输出结果: ${value}`))
.catch (err => console.log(err))


//输出
//输出结果:哎呀,她接受我了
Promise.any([
  Promise.reject('Error 1'),
  Promise.reject('Error 2'),
  Promise.reject('Error 3')
])
.then(value => console.log(`请求结果: ${value}`))
.catch (err => console.log(err))

//输出
AggregateError: All promises were rejected

Promise.any与Promise.race十分容易混淆,务必注意区分,Promise.race 一旦某个promise触发了resolve或者reject,就直接返回了该状态结果,并不在乎其成功或者失败

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

当我们通过(const、let、var)创建一个变量时,垃圾收集器GC将永远不会从内存中删除该变量,只要它的引用仍然存在可访问。WeakRef对象包含对对象的弱引用。对对象的弱引用是不会阻止垃圾收集器GC恢复该对象的引用,则GC可以在任何时候删除它。

WeakRefs在很多情况下都很有用,比如使用Map对象来实现具有很多需要大量内存的键值缓存,在这种情况下最方便的就是尽快释放键值对占用的内存。

目前,可以通过WeakMap()或者WeakSet()来使用WeakRefs

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的时候才计算赋值,只有在必要的时候才执行分配,而前者的表达式总是执行赋值操作

const pages = [
  {
    title:'主会场',
    path:'/'
  },
  {
    path:'/other'
  },
  ...
]
  
for (const page of pages){
    page.title ??= '默认标题'
}
console.table(pages)
//(index)  title            path
//0        "主会场"      "/"
//1        "默认标题"    "/other"

5. 数字分隔符

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

const money = 1_000_000_000

//等价于
const money = 1000000000

const totalFee = 1000.12_34
//等价于
const totalFee = 1000.1234
//该新特性同样支持在八进制数中使用
const number = 0o123_456
//等价于
const number = 0o123456

参考:
https://www.jianshu.com/p/13c5d002478b
https://www.jianshu.com/p/40bc10005e9e
https://www.jianshu.com/p/cf6dd11e8781
https://www.cnblogs.com/sweeeper/p/14344073.html?ivk_sa=1024320u
https://juejin.cn/post/6844903622870827022
https://www.jianshu.com/p/fc43865811d5
https://blog.csdn.net/cpongo1/article/details/89534172
https://www.jianshu.com/p/3e59df36342a
https://blog.csdn.net/qq_36958916/article/details/109490941

你可能感兴趣的:(ES7-ES12新特性)