6 月 27 日 ECMA 大会批准了 ECMAScript 2023 (es14)规范,意味着新的一些语法将正式成为标准。下面来看看 ECMAScript 2023 有哪些值得我们关注的新特性。

总览:

具体相关提案原文详情可以跳转:已完成提案

•从后往前查找数组

•Hashbang 语法

•Symbol 类型作为 WeakMap 类型的键

•不改变原数组的新的原型方法

从后往前查找数组

在 JavaScript 中,已有的 Array.prototype.find()Array.prototype.findIndex()两个方法是数组遍历中最常使用的两个方法,通常用来遍历查找数组中符合要求的项,但是目前这两种方法都是从前往后遍历的

const arr = [10, 20, 30, 40, 50];arr.find(item => item > 30); // 40arr.findIndex(item => item > 30); // 3

如果想要从后往前遍历,在以前必须先将数组进行反转,然后在对反转后的数组进行遍历查找,这无疑是非常违反直觉的事情,今年的标准就新增了两个数组遍历方法 Array.prototype.findLast()Array.prototype.findLastIndex(),通过名字也可以看出来他们的作用,用法和 findfindIndex完全一致,唯一的区别就是它是从后往前遍历的,适用于数组和类数组

findLast(): 返回第一个查找到的元素,如果没有找到,返回 undefined

findLastIndex(): 返回第一个查找到的元素的索引,如果没有找到,返回 -1

const arr = [10, 20, 30, 40, 50];arr.findLast(item => item > 30); // 50arr.findLastIndex(item => item > 30); // 4arr.findLast(item => item > 50); // undefinedarr.findLastIndex(item => item > 50); // -1

Hashbang 语法

Hashbang 注释是一种特殊的注释语法,其行为与单行注释 (//)完全一样,只是它以 #!开头,并且只在脚本或模块的最开始处有效。注意,#!标志之前不能有任何空白字符。注释由 #!之后的所有字符组成直到第一行的末尾;只允许有一条这样的注释。JavaScript 中的 hashbang 注释类似于 Unix 中的 shebang,它提供了一个特定的 JavaScript 解释器的路径,用它来执行这个脚本。

// 写在脚本文件第一行#!/usr/bin/env node'use strict';console.log(1);// 写在模块文件第一行#!/usr/bin/env nodeexport {};console.log(1);

这样就可以直接运行脚本代码了

# 以前执行脚本node demo.js# 有了 hashbang 之后执行脚本./demo.js

只有当脚本直接在 shell 中运行时,Hashbang 语法才有语意意义,其他环境下 JavaScript 解释器会把它视为普通注释。

Symbol 类型作为 WeakMap类型的键

在之前,WeakMap 类型只允许使用对象作为键,这是 WeakMap 的一个限制,新的标准扩展了 WeakMap API,允许使用唯一的 Symbol 类型作为键。这样更容易创建和共享 key。

const weakMap = new WeakMap();// 更具象征意义的keyconst key = Symbol('my ref');const someObject = { /* data */ };weakMap.set(key, someObject)

除此之外,该标准还解决了另一个在 Stage2 阶段的提案 元组与记录 中引入的问题:如何在原始数据类型中,引用和访问非原始值?由元组和记录的提案中,元组和记录类型中不能包含对象、函数和方法,当这样做时会抛出 TypeError 异常。

const server = #{  port: 8080,  handler: function (req) { /* ... */ } // TypeError}

这种限制存在是因为元组和记录提案的关键目标之一是默认保证数据的深度不可变性和结构相等性。接受 Symbol 值作为 WeakMap 键将允许 JavaScript 库实现自己的类似的 RefConllection 的东西,它可以重用的同时不会随着时间的推移泄漏内存。

class RefBookkeeper {  #references = new WeakMap();  ref(obj) {    const sym = Symbol();    this.#references.set(sym, obj);  }  deref(sym) { return this.#references.get(sym); }}globalThis.refs = new RefBookkeeper();const server = #{  port: 8080,  handler: refs.ref(function (req) { /* ... */ })}refs.deref(server.handler)({ /* ... */})

不改变原数组的新的原型方法

这次标准新增了 4 个不改变原数组的原型方法:

Array.prototype.toReversed()-> Array

Array.prototype.toSorted(compareFn)-> Array

Array.prototype.toSpliced(start, deleteCount, ...items)-> Array

Array.prototype.with(index, value)-> Array

在 JavaScript 中,数组中的大部分方法是非破坏性的,不会改变原数组,比如 filter()方法

const arr = ['a', 'b', 'b', 'c'];const result = arr.filter(x => x !== 'b');console.log(result); // ['a', 'c']

当然,也存在一些方法,是改变原数组的,比如 **sort()** 方法

const arr = ['c', 'a', 'b'];const result = arr.sort();console.log(result); // ['a', 'b', 'c']

在数组方法中,下面的方法是具有破坏性的:

reverse()

sort()

splice()

如果想要使用这些数组方法但是又不改变原数组,我们需要先创建原数组的副本,然后对数组副本使用这些方法。因此就引入了这三个方法的非破坏性的版本,就不需要再创建数组副本进行操作了。

除此之外,还有一个新的非破坏性的方法: with(index, value)。该方法会以非破坏性的方式,替换给定参数 index 位置的数组元素,即 arr[index] = value的非破坏性版本。

// toReversed()const arr = ['a', 'b', 'c'];const result = arr.toReversed();console.log(result); // ['c', 'b', 'a']console.log(arr);    // ['a', 'b', 'c']// toSorted()const arr = ['c', 'a', 'b'];const result = arr.toSorted();console.log(result);  // ['a', 'b', 'c']console.log(arr);     // ['c', 'a', 'b']// toSpliced()const arr = ['a', 'b', 'c', 'd'];const result = arr.toSpliced(1, 2, 'X');console.log(result); // ['a', 'X', 'd']console.log(arr);    // ['a', 'b', 'c', 'd'], 无法再得到已经删除的元素// with()const arr = ['a', 'b', 'c'];const result = arr.with(1, 'X');console.log(result);  // ['a', 'X', 'c']console.log(arr);     // ['a', 'b', 'c

这些方法适用于所有数组,也适用于定型数组 TypedArray。在上面提到的元组提案,这些方法也是同样适用的,元组相当于不可变的数组,所以元组不支持破坏性的方法,将这些破坏性的方法引入非破坏性的版本对元组是非常有帮助的。

End

以上就是 ES2023全部标准化的提案了,目前 Chrome 浏览器已经全部支持,可以在调试工具中尝试新的特性。

作者:京东零售 谢天