#过年不停更# 盘点2021年V8发布的新特性/API 原创
数组的 findLast 和 findLastIndex 方法
相比于数组的 find
和 findIndex
方法来说,findLast
和 findLastIndex
不同的是其查找元素的循序是从后往前查找的。
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.hasOwn
是 Object.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
不香吗
at方法
at 方法发布于 v9.2,新 at
方法可用于 Arrays
、TypedArrays
和 Strings
。当传递一个负值时,它从可索引的末尾执行相对索引。当传递一个正值时,它的行为与属性访问相同。例如,[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
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]