自ES6(ECMAScript 2015)发布以来,JavaScript每年都有重大更新,引入了一系列革命性的新特性和API,极大地提升了开发效率和代码可读性。以下是在ES6之后版本中的一些核心新特性总结。
ES7(2016)
- ** 指数运算符
let result = 2 ** 3; // 8
- Array.prototype.includes: 数组成员判断方法
[2, 3, 4].includes(2); // true
ES8(2017)
- Async/Await: 异步编程的新范式。
async function getResponse(url) {
let response = await fetch(url);
return await response.text();
}
- Object.values/Object.entries: 访问对象的所有值或键值对。
let object = {a: 1, b: 2};
let entries = Object.entries(object); // [['a', 1], ['b', 2]]
let values = Object.values(object); // [1, 2]
-
String.prototype.padStart/padEnd: 补充字符串两端空白或其他字符。
let str = "5";
// 填充到总长度为 4,使用 '0' 填充左边
let paddedStr = str.padStart(4, '0');
console.log(paddedStr); // 输出 "0005"
// 如果原字符串已经足够长,则不会做任何事情
paddedStr = "Hello".padStart(5, "Hi");
console.log(paddedStr); // 输出 "Hello"
// 可以使用任意字符填充
paddedStr = "-".padStart(4, "*-");
console.log(paddedStr); // 输出 "**-*"
// 使用点号填充
eaddedStr = "apple".padEnd(10, ".");
console.log(eaddedStr); // 输出 "apple....."
ES9(2018)
- 异步迭代器: 适用于异步数据源的迭代器。
async function* generator() {
yield 1;
yield 2;
yield 3;
}
let gen = generator();
(async () => {
while(true) {
let val = await gen.next();
if(val.done) break;
console.log(val.value);
}
})();
- Rest/Spread 属性: 剩余参数
let obj1 = {a: 1, b: 2};
let obj2 = {...obj1, c: 3}; // {a: 1, b: 2, c: 3}
- Symbols as Object keys: 使用Symbol作为对象键名。
// 创建一个Symbol类型的键
const mySymbol = Symbol();
// 使用该Symbol作为对象的键
let obj = {};
obj[mySymbol] = "Private data";
// 访问这个Symbol属性
console.log(obj[mySymbol]); // Outputs: Private data
// 验证Symbol的唯一性
let anotherSymbol = Symbol();
console.log(mySymbol === anotherSymbol); // Outputs: false
ES10 (2019)
- Array.flat & Array.flatMap: 扁平化数组。
let nestedArray = [[1, 2, [3]], [4, 5], 6];
// 默认只扁平化一层
let oneLevelFlat = nestedArray.flat();
console.log(oneLevelFlat); // [1, 2, [3], 4, 5, 6]
// 深度扁平化
let fullyFlat = nestedArray.flat(Infinity);
console.log(fullyFlat); // [1, 2, 3, 4, 5, 6]
let numbers = [1, 2, 3];
// 使用 map()
let mappedAndFlattened = numbers.map(x => [x * 2]);
console.log(mappedAndFlattened); // [[2], [4], [6]]
// 使用 flatMap()
let flatMapped = numbers.flatMap(x => [x * 2]);
console.log(flatMapped); // [2, 4, 6]
// flatMap 还能接受多个返回值,形成更深的嵌套
let deeperNested = numbers.flatMap(x => [x, [x * 2]]);
console.log(deeperNested); // [1, [2], 2, [4], 3, [6]]
- String.trimStart()和String.trimEnd():去掉开头结尾空格文本
let greeting = " Hello World! ";
console.log(greeting.trimStart()); // 输出: "Hello World! "
console.log(greeting.trimEnd()); // 输出: " Hello World!"
- String.matchAll: 获取所有匹配项的迭代器。
const emailPattern = /\S+@\S+\.\S+/g;
const text = `
John Doe <john.doe@example.com>
Jane Doe <jane@doe.org>
Another User <another.user@domain.net>
`;
for (const match of text.matchAll(emailPattern)) {
console.log(match[0]); // Logs each matched email address
}
// Output:
// john.doe@example.com
// jane@doe.org
// another.user@domain.net
ES11 (2020)
- 动态Import: 动态加载模块。
(async () => {
let module = await import('./myModule.js');
module.default();
})();
- BigInt: 支持大整数运算。
let number = 123456789012345678901234567890n;
console.log(number + 1n); // 123456789012345678901234567891n
- Promise.allSettled: 统一处理所有promise的状态。
const promise1 = Promise.resolve(3);
const promise2 = Promise.reject(new Error('Failed.'));
const promise3 = Promise.resolve(7);
// Promise.allSettled 接收这三个Promise组成的数组,并返回一个Promise,当所有的Promise都完成(无论是成功还是失败)后才解析
Promise.allSettled([promise1, promise2, promise3])
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log(`Fulfilled with ${result.value}`);
} else if (result.status === 'rejected') {
console.error(`Rejected with ${result.reason.message}`);
}
});
})
.catch(error => {
console.error('An unexpected error occurred:', error);
});
// Output will be:
// Fulfilled with 3
// Rejected with Failed.
// Fulfilled with 7
- Optional Chaining: 安全访问深层次属性。
let person = {};
console.log(person?.name); // undefined
- Nullish Coalescing Operator:
??
提供更清晰的空值处理。
let value = null ?? "default";
console.log(value); // "default"
ES12 (2021)
- String.prototype.replaceAll: 有了这个 API,替换字符不用写正则了
let str = "one, two, three, four";
let result = str.replaceAll(',', ';');
console.log(result); // 输出:"one; two; three; four"
let str = "I have 3 cats and 2 dogs.";
let result = str.replaceAll(/\d/g, '*');
console.log(result); // 输出:"I have * cats and * dogs."
- 逻辑赋值运算符:
&&= ||= ??=
,提供条件赋值。
let x = true;
x ||= false; // x remains true
x &&= false; // x becomes false
- Weak References: 更安全的对象引用管理(垃圾回收器可以自由地回收由WeakRef持有的对象)。
class MyClass {
static #weakref = null;
constructor() {
this.someProperty = {};
MyClass.#weakref = new WeakRef(this);
}
destroy() {
this.someProperty = null;
MyClass.#weakref = null; // 清除弱引用
}
static getInstance() {
return MyClass.#weakref?.deref();
}
}
const instance = new MyClass();
console.log(MyClass.getInstance()); // 输出当前实例
instance.destroy();
console.log(MyClass.getInstance()); // 输出 undefined 或可能已经GC回收
- Numeric Separators: _作为数字中的分隔符,方便阅读
let largeNumber = 1_000_000_000; // 十亿
console.log(largeNumber); // 输出: 1000000000
let price = 2_345.67; // 带小数点的数字
console.log(price); // 输出: 2345.67
let hexNumber = 0xFF_00_FF; // 十六进制数
console.log(hexNumber); // 输出: 65280
let binaryNumber = 0b_101_010_10; // 二进制数
console.log(binaryNumber); // 输出: 170
- Promise.any(): 新增Promise.any()方法,用于同时处理多个promise,只要其中一个成功就会立即解析。
const fetchUser = () => Promise.reject(new Error('User not found'));
const fetchPost = () => Promise.resolve({ post: "Hello World!" });
// 使用Promise.any()
Promise.any([fetchUser(), fetchPost()])
.then(result => {
console.log(result); // { post: "Hello World!" }
})
.catch(error => {
console.error(error); // 只有当所有Promise都reject时才会进入此catch块
});
ES13 (2022)
- Error Causation: 更详细的错误原因跟踪。
try {
throw new Error('Oops!', {cause: new SyntaxError('Invalid syntax')});
} catch(e) {
console.log(e.cause); // SyntaxError {}
}
ES14 (2023)
- 顶级Await: 在模块顶部使用await语句。
// Requires an environment that supports top-level await
await new Promise(resolve => setTimeout(resolve, 1000)).then(() => console.log('Done'));