从ES7到ES12,了解JavaScript的新特性与语法演变
⭐️ES2016(ES7):
一、Array.prototype.includes
1.1 定义
Array.prototype.includes
是一个用于判断数组是否包含特定元素的方法。它返回一个布尔值,表示数组中是否存在指定的值。
1.2 语法
arr.includes(searchElement[, fromIndex])
-
arr
: 要调用includes
方法的数组。 -
searchElement
: 要查找的元素。 -
fromIndex
(可选): 开始查找的索引位置。如果省略该参数,则从数组的开头(索引 0)开始查找。如果fromIndex
为负数,则从数组的末尾开始计算。
1.3 返回值
一个布尔值。如果数组包含指定的元素,则返回 true
,否则返回 false
。
1.4 举例
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false
console.log(numbers.includes(3, 2)); // false,从索引 2 开始查找
二、Exponentiation Operator
指数运算符
2.1 定义
Exponentiation Operator
是一个用于进行指数运算的运算符,它允许将一个数值(底数)进行指定次数的乘方运算。
2.2 语法
base ** exponent
-
base
: 底数,即要进行乘方运算的数值。 -
exponent
: 指数,表示要将底数乘方的次数。
2.3 举例
console.log(2 ** 3); // 2的3次方,输出: 8
console.log(5 ** 2); // 5的2次方,输出: 25
console.log(10 ** 0); // 任何数的0次方都为1,输出: 1
Exponentiation Operator
提供了一种简洁的语法来进行乘方运算,避免了使用 Math.pow
等其他方法。
⭐️ES2017(ES8):
一、Async functions
1.1 定义
Async functions
是 async
声明的函数,async
函数是 AsyncFunction
构造函数的实例,其中允许使用 await
关键字。
1.2 语法
async function name([param[, param[, ...param]]]) {
// statements
}
1.3 返回值
一个 Promise
1.4 示例:
async function fetchData() {
try {
console.log('Fetching data...');
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log('Data fetched successfully:', data);
return data;
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
}
fetchData();
二、Object.entries
2.1 返回值
Object.entries()
方法返回一个给定对象自身可枚举属性的键值对数组。
2.2 语法
Object.entries(obj);
2.3 示例
const obj = { a: 1, b: 2 };
const entries = Object.entries(obj);
console.log(entries); // 输出:[['a', 1], ['b', 2]]
三、Object.values
3.1 返回值
Object.values()
方法返回一个给定对象自身可枚举属性值的数组。
3.2 语法
Object.values(obj);
3.3 示例
const obj = { a: 1, b: 2 };
const values = Object.values(obj);
console.log(values); // 输出:[1, 2]
四、Object.getOwnPropertyDescriptors
4.1 返回值
Object.getOwnPropertyDescriptors()
方法用来获取一个对象的所有自身属性的描述符。
4.2 语法
Object.getOwnPropertyDescriptors(obj);
4.3 示例
const obj = { a: 1, b: 2 };
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
// 输出:
// {
// a: { value: 1, writable: true, enumerable: true, configurable: true },
// b: { value: 2, writable: true, enumerable: true, configurable: true }
// }
五、Trailing commas
尾后逗号
5.1 定义
如果你想要添加新的属性,并且在上一行已经使用了尾后逗号,你可以仅仅添加新的一行,而不需要修改上一行。
5.2 示例
// 数组
const arr = [
1,
2,
];
// 对象
const obj = {
a: 1,
b: 2,
};
// 函数参数定义
function sum(x, y,) {
return x + y;
}
// 函数调用
console.log(sum(1, 2)); // 输出:3
六、String.prototype.padStart()
6.1 定义
padStart()
用另一个字符串填充当前字符串。
6.2 返回值
在原字符串开头填充指定的填充字符串直到目标长度所形成的新字符串。
6.3 语法
str.padStart(targetLength);
str.padStart(targetLength, padString);
6.4 示例
const str = 'abc';
const paddedStr = str.padStart(10);
console.log(paddedStr); // 输出:" abc"
七、String.prototype.padEnd()
7.1 定义
padEnd()
方法会用一个字符串填充当前字符串(如果需要的话则重复填充)。
7.2 返回值
返回在原字符串末尾填充指定的填充字符串直到目标长度所形成的新字符串。
7.3 语法
str.padEnd(targetLength);
str.padEnd(targetLength, padString);
7.4 示例
const str = 'abc';
const paddedStr = str.padEnd(10);
console.log(paddedStr); // 输出:"abc "
⭐️ES2018(ES9):
一、Async iterators
异步迭代器
1.1 定义
异步迭代器是在 ES2018 中引入的一种新的迭代器类型。它允许在进行迭代时异步地获取序列的下一个值。
1.2 异步迭代器协议
异步迭代器对象必须实现一个名为 Symbol.asyncIterator
的方法,该方法返回一个异步迭代器对象。
异步迭代器对象应该实现一个名为 next
的异步方法,该方法返回一个 Promise,解析为一个包含 value
和 done
属性的对象。
-
value
:表示迭代器返回的值。 -
done
:一个布尔值,表示迭代器是否已完成迭代。
1.3 举例
// 异步迭代器示例
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
async next() {
if (i < 3) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return { value: i++, done: false };
} else {
return { done: true };
}
},
};
},
};
// 异步迭代
(async function () {
for await (const num of asyncIterable) {
console.log(num);
}
})();
二、Object rest properties
剩余属性
2.1 定义
Object rest properties
允许使用剩余语法来获取除已解构属性之外的其余属性,并将它们放置在一个新的对象中。
2.2 语法
const { prop1, prop2, ...rest } = object;
2.3 举例
const person = { name: 'John', age: 30, city: 'New York', country: 'USA' };
const { name, age, ...address } = person;
console.log(name); // 'John'
console.log(age); // 30
console.log(address); // { city: 'New York', country: 'USA' }
三、Object spread properties
扩展属性
3.1 定义
Object spread properties
允许使用扩展运算符将一个对象的所有属性拷贝到另一个对象中。
3.2 语法
const newObj = { ...obj };
3.3 举例
const defaults = { option1: true, option2: false };
const userConfig = { option2: true };
const finalConfig = { ...defaults, ...userConfig };
console.log(finalConfig);
// Output: { option1: true, option2: true }
四、Promise.prototype.finally
4.1 定义
Promise.prototype.finally
方法允许你在 Promise 完成时,无论结果是成功还是失败,都执行一些代码。
4.2 语法
promise.finally(onFinally);
-
onFinally
: 一个在 Promise 完成时执行的函数。
4.3 返回值
一个新的 Promise,由原始 Promise 完成时的值或原始错误传递。
4.4 举例
function fetchData() {
return new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
const data = Math.random();
data > 0.5 ? resolve(data) : reject('Error: Data too small');
}, 1000);
});
}
fetchData()
.then((result) => console.log('Success:', result))
.catch((error) => console.error('Error:', error))
.finally(() => console.log('Finally: Cleanup or Final Tasks'));
⭐️ES2019(ES10):
一、Array.prototype.{flat, flatMap}
扁平化嵌套数组
1.1 Array.prototype.flat
1.1.1 定义
flat()
方法会按照一个可指定的深度遍历递归数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
1.1.2 语法
arr.flat([depth]);
-
depth
是数组遍历的深度,默认是 1。
1.1.3 返回值
一个新数组,不会改变旧数组。
1.1.4 举例
const arr = [1, 2, [[[3, 4]]]];
arr.flat(); // [1, 2, [[[3, 4]]]]
arr.flat(3); // [1, 2, [3, 4]]
arr.flat(-1); // [1, 2, [[[3, 4]]]]
arr.flat(Infinity); // [1, 2, 3, 4]
1.1.5 注意
flat()
会移除数组中的空项。
let arr = [1, 2, , , 3];
arr.flat(); // [1, 2, 3]
1.1.6 替换
-
reduce
与concat
let arr = [1, 2, [3, 4]];
arr.reduce((arr, val) => arr.concat(val), []);
- 扩展运算符与
concat
let arr = [1, 2, [3, 4]];
[].concat(...arr);
1.2 Array.prototype.flatMap
1.2.1 定义
flatMap()
方法首先使用映射函数映射数组(深度值为 1)的每个元素,然后将结果压缩成一个新数组。
1.2.2 返回值
一个新数组,并且每个元素都是回调函数的结果。
1.2.3 语法
arr.flatMap(function callback(currentVal[, index[, array]]) {
}[, thisArg])
-
callback
: 可以生成一个新数组所调用的函数-
currentVal
: 当前数组在处理的元素 -
index
: 可选,正在处理的元素索引 -
array
: 可选,被调用的数组
-
-
thisArg
: 执行 callback 函数时使用的 this 值
1.2.4 举例
let arr = ['My name', 'is', '', 'Lisa'];
let newArr1 = arr.flatMap(cur => cur.split(' '));
let newArr2 = arr.map(cur => cur.split(' '));
console.log(newArr1); // ["My", "name", "is", "", "Lisa"]
console.log(newArr2); // [["My", "name"], ["is"], [""], ["Lisa"]]
二、Object.fromEntries
2.1 定义
fromEntries()
方法会把键值对列表转换成一个对象。
2.2 返回值
一个新的对象。
2.3 语法
Object.fromEntries(iterable)
-
iterable
: Array、Map 等可迭代对象
2.4 举例
let map = new Map([['a', 1], ['b', 2]]);
let mapToObj = Object.fromEntries(map);
console.log(mapToObj); // {a: 1, b: 2}
let arr = [['a', 1], ['b', 2]];
let arrToObj = Object.fromEntries(arr);
console.log(arrToObj); // {a: 1, b: 2}
let obj = {a: 1, b: 2};
let newObj = Object.fromEntries(
Object.entries(obj).map(
([key, val]) => [key, val * 2]
)
);
console.log(newObj); // {a: 2, b: 4}
三、String.prototype.{trimStart, trimEnd}
3.1 String.prototype.trimStart
3.1.1 定义
trimStart()
方法用来删除字符串的开头的空白字符。
trimLeft()
是它的别名。
3.1.2 返回值
一个新的字符串,这个字符串左边的空格已经被去除掉了。
3.1.3 语法
str.trimStart();
str.trimLeft();
3.1.4 🌰 举例
let str = ' a b cd ';
str.trimStart(); // 'a b cd '
str.trimLeft(); // 'a b cd '
3.2 String.prototype.trimEnd
3.2.1 定义
trimEnd()
方法用来删除字符串末尾的空白字符。trimRight()
是它的别名。
3.2.2 返回值
一个新的字符串,这个字符串右边的空格已经被去除了。
3.2.3 语法
str.trim
End();
str.trimRight();
3.2.4 🌰 举例
let str = ' a b cd ';
str.trimEnd(); // ' a b cd'
str.trimRight(); // ' a b cd'
四、Symbol.prototype.description
4.1 定义
description
是一个只读属性,返回 Symbol
对象的可选描述符。
4.2 语法
Symbol.prototype.description
4.3 返回值
一个可选的字符串描述符。
4.4 🌰 举例
const sym = Symbol('This is my symbol');
console.log(sym.description); // "This is my symbol"
五、Optional catch binding
5.1 定义
ES10 引入了可选的 catch 绑定,允许在 catch 块中省略异常参数。
5.2 语法
try {
// 代码块
} catch {
// 异常处理
}
5.3 举例
try {
// 可能出现异常的代码
} catch {
// 不需要异常参数了,直接处理异常
}
六、Array.prototype.sort()
6.1 定义
在 ES10 中,规范明确了 Array.prototype.sort()
方法必须使用稳定排序算法。在先前的规范中,对于没有指定排序算法的浏览器和引擎,可能使用不稳定的排序算法。稳定排序算法会保持相等元素的原始相对顺序。
6.2 示例
const arr = [{ num: 2 }, { num: 1 }, { num: 2 }, { num: 3 }];
arr.sort((a, b) => a.num - b.num);
console.log(arr);
// Output: [{ num: 1 }, { num: 2 }, { num: 2 }, { num: 3 }]
⭐️ES10(ES2019):
一、空值合并运算符(Nullish coalescing Operator)
1.1 定义
空值合并运算符(??
)是一个逻辑操作符,用于在变量为 null 或 undefined 时,提供一个默认值。
1.2 语法
const result = valueToCheck ?? defaultValue;
1.3 示例
const name = null;
const defaultName = 'John Doe';
const result = name ?? defaultName;
console.log(result); // Output: "John Doe"
const age = 0;
const defaultAge = 18;
const result2 = age ?? defaultAge;
console.log(result2); // Output: 0
二、可选链 Optional chaining
2.1 定义
可选链操作符(?.
)允许在对象链中安全地访问深层的属性或方法,当遇到 null 或 undefined 时不会抛出错误,而是返回 undefined。
2.2 语法
const result = object?.property?.nestedProperty;
2.3 示例
const person = {
name: 'John Doe',
address: {
city: 'New York',
},
};
const cityName = person?.address?.city;
console.log(cityName); // Output: "New York"
const age = person?.age;
console.log(age); // Output: undefined
三、globalThis
3.1 定义
globalThis
是一个全局对象的标准属性,用于在任何环境中获取全局对象,无论在浏览器、Web Workers、Node.js 还是其他环境中。
3.2 使用场景
在不同的环境中,获取全局对象有不同的方式:
- 在浏览器中可以使用
window
或self
- 在 Web Workers 中可以使用
self
或globalThis
- 在 Node.js 中可以使用
global
现在,可以统一使用 globalThis
来获取全局对象,无需关心当前运行环境。
3.3 示例
在浏览器中:
console.log(globalThis === window); // true
console.log(globalThis === self); // true
在 Node.js 中:
console.log(globalThis === global); // true
在 Web Workers 中:
console.log(globalThis === self); // true
四、BigInt
4.1 定义
BigInt 是一种内置对象,用于表示任意大的整数。
4.2 创建 BigInt
BigInt 可以通过在整数字面量后面加 n
来创建。
const bigIntNumber = 9007199254740991n;
或者调用函数 BigInt()
并传递一个整数值或字符串值。
const bigIntNumber2 = BigInt(9007199254740991);
const bigIntNumber3 = BigInt('9007199254740991');
4.3 示例
const a = 9007199254740991n;
const b = BigInt('9007199254740991');
const c = BigInt(9007199254740991);
console.log(a); // Output: 9007199254740991n
console.log(b); // Output: 9007199254740991n
console.log(c); // Output: 9007199254740991n
console.log(typeof a); // Output: "bigint"
五、String.prototype.matchAll()
5.1 定义
matchAll()
方法返回一个包含正则表达式全局匹配结果的迭代器。
5.2 语法
const iterator = string.matchAll(regexp);
5.3 示例
const str = 'test1test2';
const regexp = /t(e)(st(\d?))/g;
const matches = [...str.matchAll(regexp)];
for (const match of matches) {
console.log(match);
}
六、Promise.allSettled()
6.1 定义
Promise.allSettled()
方法返回一个在所有给定的 promise 都已经 fulfilled 或 rejected 后的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果。
6.2 语法
const promises = [promise1, promise2, ...];
Promise.allSettled(promises)
.then(results => {
// Handle results
})
.catch(error => {
// Handle error
});
6.3 示例
const promise1 = Promise.resolve(1);
const promise2 = Promise.reject(new Error('Error occurred'));
Promise.allSettled([promise1, promise2])
.then(results => {
console.log(results);
})
.catch(error => {
console.error(error);
});
七、Dynamic import(按需 import)
7.1 定义
Dynamic import
是一种动态导入模块的方法,它可以在需要的时候才加载模块,而不是在代码运行时一开始就加载。
7.2 语法
import(modulePath)
.then(module => {
// Use module
})
.catch(error => {
// Handle error
});
7.3 示例
button.addEventListener('click', event => {
import('./test.js')
.then(test => {
alogBox.open();
})
.catch(error => {
// Handle error
});
});
八、Promise.any
8.1 定义
Promise.any()
方法接受一组 Promise 实例作为参数,并返回一个新的 Promise 实例。该 Promise 实例在参数中的任意一个 Promise 成功(fulfilled)时变为 fulfilled 状态,如果所有参数实例都变成 rejected 状态,则返回一个 AggregateError 类型的实例,包含所有错误信息。
8.2 语法
Promise.any([promise1, promise2, ...])
.
then(result => {
// Handle the first fulfilled result
})
.catch(errors => {
// Handle errors
});
8.3 示例
const promise1 = new Promise((resolve, reject) => setTimeout(reject, 500, 'Error 1'));
const promise2 = new Promise(resolve => setTimeout(resolve, 300, 'Result 2'));
const promise3 = new Promise(resolve => setTimeout(resolve, 800, 'Result 3'));
Promise.any([promise1, promise2, promise3])
.then(result => {
console.log(result); // Output: "Result 2"
})
.catch(errors => {
console.error(errors); // Output: AggregateError: All promises were rejected
});
⭐️ES2021(ES12):
一、逻辑运算符和赋值表达式
1.1 定义
ES12 引入了逻辑运算符和赋值表达式的组合,这些运算符方便地对变量进行条件赋值操作。
1.2 语法
-
&&=
:逻辑与赋值表达式,将右侧的值赋给左侧的变量,但仅当左侧的变量在布尔上下文中为真时。 -
||=
:逻辑或赋值表达式,将右侧的值赋给左侧的变量,但仅当左侧的变量在布尔上下文中为假时。 -
??=
:空值合并赋值表达式,将右侧的值赋给左侧的变量,但仅当左侧的变量为 null 或 undefined 时。
1.3 示例
let x = 5;
let y = 10;
// 逻辑与赋值表达式
x &&= y;
console.log(x); // Output: 10 (因为 x 为真,所以将 y 赋给 x)
let a = 0;
let b = 20;
// 逻辑或赋值表达式
a ||= b;
console.log(a); // Output: 20 (因为 a 为假,所以将 b 赋给 a)
let foo = null;
let bar = 'Hello';
// 空值合并赋值表达式
foo ??= bar;
console.log(foo); // Output: "Hello" (因为 foo 为 null,所以将 bar 赋给 foo)
二、String.prototype.replaceAll()
2.1 定义
String.prototype.replaceAll()
方法用于替换字符串中所有匹配的子字符串,类似于 String.prototype.replace()
,但是会替换所有匹配,而不仅仅是第一个匹配。
2.2 语法
const newStr = originalStr.replaceAll(searchValue, replaceValue);
2.3 示例
const str = 'Hello, hello, hello';
const newStr = str.replaceAll('hello', 'Hi');
console.log(newStr); // Output: "Hello, Hi, Hi"
三、数字分隔符
3.1 定义
数字分隔符是一种增强的数值表示法,可以在数字中使用下划线 _
进行分隔,以提高数字的可读性。
3.2 示例
const billion = 1_000_000_000;
const pi = 3.14_15_92_65;
console.log(billion); // Output: 1000000000
console.log(pi); // Output: 3.14159265