从ES7到ES10的新特性大总结

173 阅读6分钟

一、ES7 (ES2016)

1. 指数运算符 (**)

ES7 引入了指数运算符 **,它使得执行幂运算更加简洁和直观。在此之前,我们通常使用 Math.pow() 来实现同样的功能。

语法:

let result = base ** exponent;

示例:

console.log(2 ** 3); // 输出: 8
console.log(4 ** 0.5); // 输出: 2

2. Array.prototype.includes()

ES7 还引入了 Array.prototype.includes() 方法,用于判断数组是否包含某个指定的值。如果包含,则返回 true,否则返回 false。这个方法解决了之前需要手动遍历数组或使用其他复杂方法来检查元素存在的问题。

语法:arr.includes(searchElement[, fromIndex])

  • searchElement: 必需。要在数组中查找的元素。
  • fromIndex: 可选。开始搜索的位置。默认从索引 0 开始。如果为负数,则表示从数组末尾开始计算位置。

示例:

let fruits = ['apple', 'banana', 'orange'];
console.log(fruits.includes('banana')); // 输出: true
console.log(fruits.includes('grape')); // 输出: false
console.log(fruits.includes('apple', 1)); // 输出: false (从索引1开始查找)

二、ES8新特性(2017)

1. 异步函数 (Async/Await)

异步函数是ES8中最令人兴奋的新特性之一。它使得处理异步操作变得更加直观和简洁。async关键字用于定义一个异步函数,而await关键字用于等待Promise的结果。

async function fetchData(url) {
  try {
    const response = await fetch(url);
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

fetchData('https://api.example.com/data')
  .then(data => console.log(data))
  .catch(error => console.error(error));

2. 对象属性的扩展 (Object Property Shorthand)

ES8进一步简化了对象字面量的语法,允许直接使用变量名作为对象的属性名。

const name = 'Alice';
const age = 30;

const person = { name, age };
console.log(person); // { name: 'Alice', age: 30 }

3. 字符串填充 (String Padding)

ES8引入了两个新的字符串方法:padStartpadEnd,用于在字符串的开头或结尾添加指定的字符,直到达到指定的长度。

const str = 'Hello';

console.log(str.padStart(10, '*')); // '*****Hello'
console.log(str.padEnd(10, '*'));   // 'Hello*****'

4. Object.values 和 Object.entries

这两个方法分别返回对象自身的可枚举属性值和键值对数组。

const obj = { a: 1, b: 2, c: 3 };

console.log(Object.values(obj)); // [1, 2, 3]
console.log(Object.entries(obj)); // [['a', 1], ['b', 2], ['c', 3]]

5. 共享内存和原子操作 (Shared Memory and Atomics)

ES8引入了SharedArrayBufferAtomics对象,用于实现多线程环境下的共享内存和原子操作。

const sab = new SharedArrayBuffer(1024);
const int32View = new Int32Array(sab);

Atomics.add(int32View, 0, 1);
console.log(Atomics.load(int32View, 0)); // 1

6. 函数参数列表和调用中的尾逗号

ES8允许在函数参数列表和调用中使用尾逗号,这使得代码更易读且便于维护。

function myFunction(a, b, c,) {
  console.log(a, b, c);
}

myFunction(1, 2, 3,);

三、ES9新特性(2018)

1. 异步迭代(Async Iteration)

在ES6中,引入了同步迭代的概念,而ES8则引入了Async操作符。在此基础上,ES9引入了异步遍历的新特性——Async Iteration。这一特性允许async/awaitfor-of一起使用,以串行的方式运行异步操作,达到异步函数的迭代效果。例如:

async function process(array) {   
  for await (let i of array) {   
    doSomething(i);    }
}

这一特性使得处理异步数据流变得更加直观和方便。

2. Promise.finally()

在ES6中,一个Promise链要么成功进入最后一个then(),要么失败触发catch()。然而,在实际应用中,我们可能需要在Promise无论成功还是失败时都运行相同的代码,例如清除资源、删除会话、关闭数据库连接等。ES9引入了finally()方法,允许指定无论Promise成功还是失败都要执行的逻辑。例如:

test()
  .then((result) => {})
  .catch((err) => {})    
  .finally(() => {});

finally()方法的引入,使得Promise的处理更加灵活和健壮。

3. Rest/Spread属性

Rest和Spread操作符在ES6中是以...的形式引入的,但当时仅适用于数组。在ES9中,这两个操作符被扩展到了对象上。

  • Rest操作符:主要用于对象的解构,可以拷贝对象除了已手动指定的属性名之外的所有可枚举属性。例如:
const obj = {foo: 1, bar: 2, baz: 3};
const {foo, ...rest} = obj;
// 等同于:
// const foo = 1;
// const rest = {bar: 2, baz: 3};
  • Spread操作符:主要用于字面量对象的构建,可以展开对象的所有可枚举属性。例如:
const obj = {foo: 1, bar: 2};
const newObj = {...obj, baz: 3};
// 结果为:{foo: 1, bar: 2, baz: 3}

Rest和Spread操作符的引入,使得对象的解构和构建变得更加简洁和灵活。

4. 正则表达式新特性

ES9的正则表达式也引入了一些新特性,包括命名捕获组、反向断言、新增标记s以及Unicode转义。

  • 命名捕获组:允许给匹配项命名,并通过groups对象访问这些命名捕获组。例如:
const reDate = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = reDate.exec('2018-08-06');console.log(match.groups.year); 
// 输出:2018
  • 反向断言:包括先行断言和反向断言,用于在匹配过程中进行更复杂的条件判断。
  • 新增标记s:允许.匹配包括换行符在内的任何字符。
  • Unicode转义:允许使用\p{...}\P{...}进行Unicode字符的匹配和排除。

这些正则表达式的新特性,使得字符串的处理和匹配变得更加强大和灵活。

四、ES10(ES2019)

1. Array.prototype.flatArray.prototype.flatMap

Array.prototype.flat 方法用于将嵌套的数组“扁平化”,即将其展开为一维数组。你可以指定一个深度参数来控制展开的层数,默认值为 1。

const arr = [1, 2, [3, 4, [5, 6]], 7];
const flatArr = arr.flat(); // [1, 2, 3, 4, [5, 6], 7]
const deepFlatArr = arr.flat(2); // [1, 2, 3, 4, 5, 6, 7]

Array.prototype.flatMap 方法结合了 mapflat 的功能,先对每个元素进行映射操作,然后将结果展平。

const arr = [1, 2, 3, 4];
const mappedAndFlattened = arr.flatMap(x => [x * 2]); // [2, 4, 6, 8]

2. Object.fromEntries

Object.fromEntries 方法用于将键值对列表转换为对象。它与 Object.entries 方法相反。

const entries = [['name', 'Alice'], ['age', 25]];
const obj = Object.fromEntries(entries); // { name: 'Alice', age: 25 }

3. String.prototype.trimStartString.prototype.trimEnd

这两个方法分别用于去除字符串开头和结尾的空白字符。它们是 trimLefttrimRight 的别名,以提高命名的一致性。

const str = '   Hello, World!   ';
const trimmedStart = str.trimStart(); // 'Hello, World!   '
const trimmedEnd = str.trimEnd(); // '   Hello, World!'

4. Symbol.prototype.description

Symbol.prototype.description 属性返回符号的描述字符串。如果在创建符号时没有提供描述,则返回 undefined

const sym1 = Symbol('foo');
console.log(sym1.description); // 'foo'

const sym2 = Symbol();
console.log(sym2.description); // undefined

5. Function.prototype.toString 的改进

Function.prototype.toString 方法现在能够更准确地反映函数的源代码,包括箭头函数、生成器函数和异步函数。

const func = () => {
  return 42;
};
console.log(func.toString()); // '() => {\n  return 42;\n}'

6. try...catch 语句的改进

ES10 对 try...catch 语句进行了改进,允许在 catch 子句中直接捕获错误的原因,而不需要显式声明变量。

try {
  throw new Error('Something went wrong');
} catch (error) {
  console.error(error.message); // 'Something went wrong'
}