盘点2021年V8发布的新特性和API (ES2021)

·  阅读 1483
盘点2021年V8发布的新特性和API (ES2021)

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

盘点一下2021年V8发布的各大版本中对 JavaScript 开发者产生影响的特性、API都有哪些,在最新的 chrome 中这些更新都已经可用,大家可以尽情尝试。

数组的 findLast 和 findLastIndex 方法

相比于数组的 findfindIndex 方法来说,findLastfindLastIndex 不同的是其查找元素的循序是从后往前查找的。

Arrar.prototype.find 返回第一个符合条件的元素

Arrar.prototype.findIndex 返回第一个符合条件的元素的下标

Arrar.prototype.findLast 返回从后往前第一个符合条件的元素,相对于 find 来说也就是 最后一个符合条件的元素

Arrar.prototype.findLastIndex 同上,返回最后一个符合条件的元素的下标

let arr = [1,2,3,4,5]

arr.find(item => item%2===0) // 2
arr.findIndex(item => item%2===0) // 1

arr.findLast(item => item%2===0) // 4
arr.findLastIndex(item => item%2===0) // 3
复制代码

静态代码块

对于定义类的静态方法/属性相信大家都可以 手拿把掐 了,V8 在 v9.4 的版本中添加了对静态代码块的支持。静态代码块只会运行一次

他的运行时机是在类被解析后即刻运行。

这虽然与java不一致,但是对于JavaScript来说很合理,因为JavaScript是解释形语言,没有类加载机制。

静态代码块会产生自己的作用域,其 this静态方法 中的 this 一致,都指向类本身

console.log(1);
class Person {
    static {
        console.log('女娲创造了人');
        console.log(this === Person); // true
    }

    constructor (name) {
        this.name = name;
    }
}
console.log(2);
复制代码

Object.hasOwn

Object.hasOwnObject.prototype.hasOwnProperty.call 的别名,用于检测一个对象是否包含某个属性,其第一个参数是被检测的对象,第二个参数是需要检测的属性。

let obj = { prop: 42 };

obj.hasOwnProperty('prop')// true

Object.prototype.hasOwnProperty.call(obj, 'prop')
Object.hasOwn(obj, 'prop')// true
复制代码

个人感觉这个方法比较鸡肋,在js中所有的东西都属于 Object,必然都存在 hasOwnProperty 方法,到底是什么场景会有人去通过 Object.prototype.hasOwnProperty.call 的方式来判断呢?直接调用 hasOwnProperty 不香吗

关于为什么要使用 Object.prototype.hasOwnProperty.call 而不直接调用 hasOwnProperty?

因为 hasOwnProperty 作为对象的一个方法,任何一个对象都有重写 hasOwnProperty 方法的可能性,这导致 hasOwnProperty 的结果不一定可信,也就是不安全,例如下面这些情况。

let obj = {"hasOwnProperty": 1}
obj.hasOwnProperty("a")// 报错
// Uncaught TypeError: obj.hasOwnProperty is not a function

obj.hasOwnProperty = function(){return true}
obj.hasOwnProperty("a")// 期待返回 false ,但返回的是 true
复制代码

所以我们建议调用 Object.prototype 下的 hasOwnProperty 来解决这个问题

当然如果 Object.prototype 的 hasOwnProperty 也被重写了那就没办法了

let obj = {"hasOwnProperty": 1}
Object.prototype.hasOwnProperty.call(obj, "a")// false

obj.hasOwnProperty = function(){return true}
Object.prototype.hasOwnProperty.call(obj, "a")// false
复制代码

at方法

at 方法发布于 v9.2,新 at 方法可用于 ArraysTypedArraysStrings。当传递一个负值时,它从可索引的末尾执行相对索引。当传递一个正值时,它的行为与属性访问相同。例如,[1,2,3].at(-1)3

at 方法的出现是为了方便的访问数组的索引,at 方法传入一个负数时,可以表示取倒数第几个元素,这解放了我们 arr[arr.lenght-1] 的写法

let arr = [1,2,3,4,5]

arr.at(-1); // 5
arr.at(0); // 1
arr.at(4); // 5
arr.at(5); // undefined
复制代码

顶层 await

顶级await使开发人员能够在全局作用域使用 await 关键字。它就像一个将全局代码包裹一个大的 async 函数。它其实在2019年就已经诞生了,但是不是默认开启的,直到 v9.1 时 V8 才将其设置为默认开启。

以前

顶层await 支持以前,在全局代码中使用 await 会导致 SyntaxError

// test.js
await Promise.resolve(console.log('🎉'));
// → SyntaxError: await is only valid in async function

(async function() {
  await Promise.resolve(console.log('🎉'));
  // → 🎉
}());
复制代码

现在

现在的 顶层await 可以支持在全局代码中使用 await

// test.js
await Promise.resolve(console.log('🎉'));
// → 🎉

(async function() {
  await Promise.resolve(console.log('🎉'));
  // → 🎉
}());
复制代码

注意: 顶级await 适用于模块的顶级。不支持普通的函数中使用

例子

在你使用import() 来动态导入依赖的时候我觉得非常有用。

const strings = await import(`/i18n/${navigator.language}`);
复制代码

或者在你的模块需要初始化某些异步事件才能使用时,如果初始化失败时可以产生错误。

const connection = await dbConnector();
复制代码

示例:尝试从 CDN A 加载 JavaScript 库,如果失败则回退到 CDN B:

let jQuery;
try {
  jQuery = await import('https://cdn-a.example.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.example.com/jQuery');
}
复制代码

in 运算符支持检测私有属性

in 运算符可以用于检测一个对象上是否包含某个属性

const o1 = {'foo': 0};
console.log('foo' in o1); // true
const o2 = {};
console.log('foo' in o2); // false
const o3 = Object.create(o1);
console.log('foo' in o3); // true
复制代码

但是在 js 支持使用 # 开头的属性或者方法名来定义私有属性/方法后。in 运算符无法检测到 私有属性。

class User {
    #password;// 私有属性必须明确定义,否则无法通过this.#password获取
    constructor (username, password) {
        this.username = username;
        this.#password = password;
    }
}

let yuexi = new User('yuexi', '123');

yuexi.username // yuexi
'username' in yuexi // true

yuexi.password // undefined
yuexi['#password'] // undefined
'#password' in yuexi // false
'password' in yuexi // false
复制代码

在 v9.1 版本中, V8 对 in 运算符增加的检测私有属性的支持。但是这任然只能在 class 内部使用

class User {
    #password;
		
  	static hasPassword(obj){
      return #foo in obj;
    }
}
复制代码

有几点需要额外注意:

extends 关键字实现的继承中,子类实例从父类接收私有字段作为自己的属性,所以其所有的子类都可以被 in 运算符检测到私有属性

class SubA extends User {};
A.hasPassword(new SubA()); // true
复制代码

但是如果通过 原型链/寄生等方式实现的继承时,in 运算符无法检测到其父类的私有属性,因为 in 运算符不会对其原型链进行查找。

const a = new User();
const o = Object.create(a);
A.hasPassword(o); // false, 私有字段是继承的而不是本身拥有的
A.hasPassword(o.__proto__); // true
复制代码

正则表达式索引

从 v9.0 开始,开发人员可以选择在正则表达式匹配中获取匹配 的开始和结束位置的数组。当正则表达式具有/d标志时,其匹配结果的 indices 属性会存储这个数组。

const re = /(a)(b)/d;      // Note the /d flag.
const m = re.exec('ab');
console.log(m.indices[0]); // Index 0 是整个被匹配的下标信息
// → [0, 2]
console.log(m.indices[1]); // Index 1 是第一个组的下标信息
// → [0, 1]
console.log(m.indices[2]); // Index 2 是第2个组的下标信息
// → [1, 2]
复制代码
分类:
前端
分类:
前端
收藏成功!
已添加到「」, 点击更改