这是我参与「第四届青训营 」笔记创作活动的的第18天
ES7
指数运算符**
新增指数运算符**,也叫幂运算符,与Math.pow()有着一样的功能。
console.log(2**3) // 8
Array.prototype.includes()
数组原型上增加了includes()方法,该方法用于判断一个数组中是否包含指定的值,返回一个布尔值
const arr = [-0, 2, 3, 4, 5, NaN]
console.log(arr.indexOf(NaN)) // -1
console.log(arr.includes(NaN)) // true
console.log(arr.indexOf(+0)) // 0
console.log(arr.includes(+0)) // true
ES8
async/await语法糖
Promise的出现虽然解决了回调地狱的问题,但是如果链式调用特别多的话可读性还是会变差,在ES8中新增了async/await语法糖解决了这个问题。
;(async function () {
function promise(v) {
return new Promise((resolve, reject) => {
resolve(v)
})
}
const r1 = await promise(1)
const r2 = await promise(r1)
const res = await promise(r2)
console.log(res)
})()
注意:ES13中可以单独使用await,而不需要配到async了
对象扩展
Object扩展了三个静态方法
Object.values():返回一个给定对象自身的所有可枚举属性值的数组;Object.entries():返回一个给定对象自身可枚举属性的键值对数组;Object.getOwnPropertyDescriptors():返回给定对象所有自有属性的属性描述符。
字符串扩展
String.prototype新增了两个方法
padStart():在字符串开头填充空格;padEnd():在字符串结尾填充空格;
const str = 'abc'
console.log(str.padStart(10)) /* abc */
console.log(str.padEnd(10)) /* abc */
ES9
异步迭代
新增了for await...of语句,该用于可以遍历异步可迭代对象
const p1 = Promise.resolve().then(() => 1).finally(() => console.log(4));
const p2 = Promise.resolve().then(() => 2);
const p3 = Promise.resolve().then(() => 3);
;(async () => {
var p_arr = [p1, p2, p3]
for await (const p of p_arr) {
console.log(p); //1,2,3,
}
for (const p of p_arr) {
console.log(p); //p1, p2, p3
}
})();
Promise.prototype.finally()
finally()方法会返回一个Promise对象,当promise的状态变更,不管是变成rejected或者fulfilled,最终都会执行finally()的回调。
fetch('')
.then(res => {
console.log(res)
})
.catch(error => {
console.log(error)
})
.finally(() => {
console.log('结束')
})
对象展开运算符
ES6中新增数组的展开运算符,在ES9中将这一特性加入到了对象中
const a = {
a: 'a'
};
const b = {
b: 'b'
};
const c = {...a, ...b};
console.log(c.a, c.b); // a b
正则的扩展
正则表达式分组命名:
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
const matchObj = RE_DATE.exec('2022-08-17')
const year = matchObj.groups.year // 2022
const month = matchObj.groups.month // 02
const day = matchObj.groups.day // 22
ES10
Object.fromEntries()
Object.fromEntries()方法把键值对列表转换为一个对象。是Object.entries()方法的逆操作。
const person = {
name: 'name',
age: 20,
}
const e = Object.entries(person)
/*
(2) [Array(2), Array(2)]
0: (2) ['name', 'name']
1: (2) ['age', 20]
*/
const p = Object.fromEntries(e)
// {name: 'name', age: 20}
trimStart()/trimLeft()和trimEnd()/trimRight()
String.prototype.trimStart:用于去除字符串左边的空格String.prototype.trimLeft:它是trimStart的别名。String.prototype.trimEnd:用于去除字符串右边的空格String.prototype.trimRight:它是trimEnd的别名。
数组的扩展
在ES2019中扩展了两个数组方法,分别是:
Array.prototype.flat():该方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回;简单的说就是实现数组的扁平化。
const arr = [1, 2, [3, 4, [5, [6, 7]]]];
console.log(arr.flat(0)); // [1, 2, [3, 4, [5, [6, 7]]]]
console.log(arr.flat(1)); // [1, 2, 3, 4, [5, [6, 7]]]
console.log(arr.flat(2)); // [1, 2, 3, 4, 5, [6, 7]]
console.log(arr.flat(3)); // [1, 2, 3, 4, 5, 6, 7]
Array.prototype.flatMap():该方法映射且扁平化数组,返回新数组(只能展开一层数组)。
ES11
BigInt数据类型
BigInt的出现时解决JavaScript中允许的最大数字是2**53-1的问题,BigInt 可以表示任意大的整数。
const big = 111111111111111111111111111111111111111n;
const bigg = new BigInt(111111111111111111111111111111111111111);
// ↪ 111111111111111111111111111111111111111n
动态导入
动态导入,也就是我们需要该模块的时候才会进行加载,这可以减少开销和页面加载时间。使用import()方法,它返回一个Promise。
import('module.js').then(module => {
// Do something with the module.
})
同时还为import增加一个meta对象,该对象给JavaScript模块暴露了特定上下文的元数据属性的对象。
GlobalThis
globalThis是对全局对象的引入。在Node是的全局对象是Global,而浏览器环境是Window。
// 浏览器中尝试
console.log(globalThis === window); // true
空值合并运算符
空值合并运算符是由两个问号来表示,该运算符也是一个逻辑运算符,该运算符与逻辑或运算符类似。
其计算规则为,只要左运算元为null或者undefined,则返回右运算元,否则返回左运算元。而逻辑或运算符只有左运算元转换为boolean类型后为false,就返回右运算元。
示例代码如下:
console.log(null ?? 10) // 10
console.log(undefined ?? 10) // 10
console.log(false ?? 10) // false
console.log(null || 10) // 10
console.log(undefined || 10) // 10
console.log(false || 10) // 10
该运算符用于为没有值的变量赋值很有用,例如:如果这个数没有值,就为其赋值,否则不赋值,
示例代码如下:
var value = false
// 不存在value,才会赋值
value = value ?? 10
console.log(value) // 10
var value = false
// 只要类型转换后为false就会赋值
value = value || 10
console.log(value) // 10
undefined
值得注意的是空值合并运算符与逻辑与和逻辑或不能同时使用,否则会抛出异常,解决方案是通过使用
()来表明优先级
可选链操作符
可选链 ?. 是一种访问嵌套对象属性的安全的方式。即使中间的属性不存在,也不会出现错误。
例如我们想要访问A.a.b这个属性时,我们首先需要确保A存在,然后需要确保A.a存在,才可以访问A.a.b这个属性,不然就会报错。
使用可选链操作符就不会出现这样的问题,当我们访问某个属性时,只要有一处不存在,就会返回undefind,不会报错。
不要过度使用可选链
我们应该只将
?.使用在一些东西可以不存在的地方。例如,如果根据我们的代码逻辑,
user对象必须存在,但address是可选的,那么我们应该这样写user.address?.street,而不是这样user?.address?.street。那么,如果
user恰巧为 undefined,我们会看到一个编程错误并修复它。否则,如果我们滥用?.,会导致代码中的错误在不应该被消除的地方消除了,这会导致调试更加困难。
?.前的变量必须已声明如果未声明变量
user,那么user?.anything会触发一个错误:// ReferenceError: user is not defined user?.address;
?.前的变量必须已声明(例如let/const/var user或作为一个函数参数)。可选链仅适用于已声明的变量。
可选链 ?. 语法有三种形式:
obj?.prop—— 如果obj存在则返回obj.prop,否则返回undefined。obj?.[prop]—— 如果obj存在则返回obj[prop],否则返回undefined。obj.method?.()—— 如果obj.method存在则调用obj.method(),否则返回undefined。
ES12
String.prototype.replaceAll()
replaceAll()方法返回一个新字符串,新字符串的内容是经过替换的
const str = 'aabbbcccddd'
const newStr = str.replaceAll('a', 'e')
const newStr = str.replaceAll(/c/g, 'f') // 可以配合全局正则使用
console.log(newStr) // aabbbfffddd
注意
如果不使用全局正则,则会报错:
Uncaught TypeError: String.prototype.replaceAll called with a non-global RegExp argument
数值分隔符
使数值更便于阅读。用_标识。
const x = 10_0_0_0000_0;
const y = 100_000_000;
x === 100000000; // true
y === x; // true
逻辑赋值操作符
&&=||=??=
ES13
类(Class)
constructor
ES13之前类(class)的声明需要依靠constructor来基本定义和生成实例,而在ES13后就不需要这个方法了
class C {
myName = 'name'
}
/* 两者是一致的 */
class C {
constructor() {
myName = 'name'
}
}
私有字段
private修饰符只能在 TypeScript 文件中使用。
而在ES13后,使用#开头的变量则被认为使私有变量。
class a {
#a = 1;
getA() {
return this.#a;
}
}
new a().#a; // 属性 "#a" 在类 "a" 外部不可访问,因为它具有专用标识符。
new a().getA(); // 1
正则表达式
正则表达式增加了一个/d修饰符,当使用正则表达式的exec()方法时,如果有/d修饰符,那么结果会多返回一个indices属性,用来表示匹配的结果的在原字符串中的起始index值。
const str = 'test1testtttt2'
const re= /\d/d
const res = re.exec(str)
console.log(res.indices[0]) // [4,5]
await在顶层使用
允许在顶层使用await,在顶层可以不使用async函数进行包裹。
Array.prototype.at()
类似python中用负数下标。
// 返回数组倒数第二项
const arr = [1,2,3,4,5,6,7]
// 之前
arr[arr.length - 2];
// 如果使用FP,前面的arr可能是特别长的表达式,这时候需要使用slice来实现
arr.join('').split('').slice(-2, -1)[0];
// 有了新方法后
arr.at(-2)
Object.hasOwn()
判断某个对象上是否具有某个属性。
const person = {
name: 'name',
age: 20,
}
// 过去
person.name && console.log(person.name)
// 现在
Object.hasOwn(person, 'name') && console.log(person.name)
总结
从ES6开始JavaScript新增了大量新规范、语法糖和有用的方法。每一年的新规范都包含了全球各地JSer在长期code中的心酸苦楚。了解ESNext历程中的种种新规范,理清楚这里面的脉络,对我们的JS学习也是大有脾益。