JavaScript:从 ES2016 到 ES2019 的所有内容

2025-05-24

JavaScript:从 ES2016 到 ES2019 的所有内容

大家好,我是 Alberto Montalesi,一位自学成才的全栈开发者。我在我的网站inspiredwebdev.com上创建实用的 JavaScript 教程和课程,旨在激励其他开发者成长,并打造他们理想的职业。

JavaScript是一种不断发展的语言,在过去的几年中,许多新功能被添加到ECMAScript规范中。

本文摘自我的书《现代 JavaScript 完全指南》,其中涵盖了 ES2016、ES2017、ES2018、ES2019 的新增内容,最初发布在我的博客inspiredWebDev上。

在文章的最后,您将找到一个下载总结所有内容的备忘单的链接。

ES2016 的所有新功能

ES2016 仅引入了两个新功能:

  • Array.prototype.includes()
  • 指数运算符

Array.prototype.includes()

如果我们的数组包含某个元素,则includes()方法将返回,否则返回。truefalse

let array = [1,2,4,5];

array.includes(2);
// true
array.includes(3);
// false

结合includes()fromIndex

我们可以提供.includes()索引来开始搜索元素。默认值为 0,但也可以传递负值。

我们传入的第一个值是要搜索的元素,第二个值是索引:

let array = [1,3,5,7,9,11];

array.includes(3,1);
// find the number 3 starting from array index 1
// true
array.includes(5,4);
//false
array.includes(1,-1);
// find the number 1 starting from the ending of the array going backwards
// false
array.includes(11,-3);
// true

array.includes(5,4);返回的false原因是,尽管数组包含数字 5,但它位于索引 2 处,而我们开始查看位置 4。这就是为什么我们找不到它并且它返回的原因false

array.includes(1,-1);返回false是因为我们从索引 -1(数组的最后一个元素)开始查看,然后从该点继续向前。

array.includes(11,-3);返回true是因为我们回到索引 -3 并向上移动,在路径上找到了值 11。

指数运算符

在 ES2016 之前,我们会做以下事情:

Math.pow(2,2);
// 4
Math.pow(2,3);
// 8

现在使用新的指数运算符,我们可以执行以下操作:

2**2;
// 4
2**3;
// 8

当组合多个操作时它会变得非常有用,如下例所示:

2**2**2;
// 16
Math.pow(Math.pow(2,2),2);
// 16

使用时,Math.pow()你需要不断地将它们连接起来,这会变得非常冗长和混乱。指数运算符提供了一种更快、更简洁的方式来完成同样的操作。

ES2017字符串填充Object.entries()Object.values()

ES2017 引入了许多很酷的新功能,我们将在这里看到。

字符串填充(.padStart().padEnd()

我们现在可以在字符串的末尾(.padEnd())或开头(.padStart())添加一些填充。

"hello".padStart(6);
// " hello"
"hello".padEnd(6);
// "hello "

我们指定了 6 作为填充,那么为什么在两种情况下都只得到了 1 个空格呢?
这是因为padStartpadEnd会去填充空格。在我们的例子中,“hello”有 5 个字母,而我们的填充是 6,所以只留下 1 个空格。

看这个例子:

"hi".padStart(10);
// 10 - 2 = 8 empty spaces
// "        hi"
"welcome".padStart(10);
// 10 - 6 = 4 empty spaces
// "   welcome"

右对齐padStart

padStart如果我们想右对齐某些内容,我们可以使用。

const strings = ["short", "medium length", "very long string"];

const longestString = strings.sort(str => str.length).map(str => str.length)[0];

strings.forEach(str => console.log(str.padStart(longestString)));

// very long string
//    medium length
//            short

首先,我们取出最长的一根绳子并测量它的长度。然后,我们padStart根据最长绳子的长度对所有绳子应用了a,这样现在所有绳子都完美地向右对齐了。

向填充添加自定义值

我们不必只添加空格作为填充,我们可以传递字符串和数字。

"hello".padEnd(13," Alberto");
// "hello Alberto"
"1".padStart(3,0);
// "001"
"99".padStart(3,0);
// "099"

Object.entries()Object.values()

让我们首先创建一个对象。

const family = {
  father: "Jonathan Kent",
  mother: "Martha Kent",
  son: "Clark Kent",
}

在以前的版本中,JavaScript我们会像这样访问对象内部的值:

Object.keys(family);
// ["father", "mother", "son"]
family.father;
"Jonathan Kent"

Object.keys()仅返回我们必须用来访问值的对象的键。

我们现在有两种访问对象的方法:

Object.values(family);
// ["Jonathan Kent", "Martha Kent", "Clark Kent"]

Object.entries(family);
// ["father", "Jonathan Kent"]
// ["mother", "Martha Kent"]
// ["son", "Clark Kent"]

Object.values()返回所有值的数组,同时Object.entries()返回包含键和值的数组数组。

Object.getOwnPropertyDescriptors()

此方法将返回对象的所有自身属性描述符。它可以返回
属性有valuewritablegetsetconfigurableenumerable

const myObj = {
  name: "Alberto",
  age: 25,
  greet() {
    console.log("hello");
  },
}
Object.getOwnPropertyDescriptors(myObj);
// age:{value: 25, writable: true, enumerable: true, configurable: true}

// greet:{value: ƒ, writable: true, enumerable: true, configurable: true}

// name:{value: "Alberto", writable: true, enumerable: true, configurable: true}

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

这只是语法上的一个小改动。现在,在编写对象时,我们可以在每个参数后留一个逗号,无论它是否是最后一个参数。

// from this
const object = {
  prop1: "prop",
  prop2: "propop"
}

// to this
const object = {
  prop1: "prop",
  prop2: "propop",
}

注意我在第二个属性的末尾加了一个逗号。
如果不加逗号,也不会报错,但最好还是遵循这个做法,这样可以方便你的同事或团队成员。

// I write
const object = {
  prop1: "prop",
  prop2: "propop"
}

// my colleague updates the code, adding a new property
const object = {
  prop1: "prop",
  prop2: "propop"
  prop3: "propopop"
}
// Suddenly, he gets an error because he did not notice that I forgot to leave a comma at the end of the last parameter.

共享内存和Atomics

来自MDN

共享内存时,多个线程可以读写内存中的相同数据。原子操作可确保写入和读取的值是可预测的,操作在下一个操作开始之前完成,并且操作不会被中断。

Atomics不是构造函数,它的所有属性和方法都是静态的(就像Math),因此我们不能将它与新运算符一起使用或将Atomics对象作为函数调用。

其方法示例如下:

  • 添加/订阅
  • 与/或/异或
  • 加载/存储

原子与(通用固定长度二进制数据缓冲区)对象一起使用,SharedArrayBuffer这些对象表示通用的、固定长度的原始二进制数据缓冲区。

让我们看一些Atomics方法的示例:

Atomics.add()Atomics.sub()Atomics.load()Atomics.store()

Atomics.add()将采用三个参数:一个数组、一个索引和一个值,并在执行加法之前返回该索引处的先前值。

// create a `SharedArrayBuffer`
const buffer = new SharedArrayBuffer(16);
const uint8 = new Uint8Array(buffer);

// add a value at the first position
uint8[0] = 10;

console.log(Atomics.add(uint8, 0, 5));
// 10

// 10 + 5 = 15
console.log(uint8[0])
// 15
console.log(Atomics.load(uint8,0));
// 15

如您所见,调用Atomics.add()将返回我们所针对的数组位置的先前值。当我们再次调用时,uint8[0]我们会看到执行了加法并得到了 15。

要从数组中检索特定值,我们可以使用Atomics.load并传递两个参数、一个数组和一个索引。

Atomics.sub()工作方式相同,Atomics.add()但它会减去一个值。

// create a `SharedArrayBuffer`
const buffer = new SharedArrayBuffer(16);
const uint8 = new Uint8Array(buffer);

// add a value at the first position
uint8[0] = 10;

console.log(Atomics.sub(uint8, 0, 5));
// 10

// 10 - 5 = 5
console.log(uint8[0])
// 5
console.log(Atomics.store(uint8,0,3));
// 3
console.log(Atomics.load(uint8,0));
// 3

这里我们使用Atomics.sub()从位置的值中减去 5,uint8[0]相当于 10 - 5。
与 相同Atomics.add(),该方法将返回该索引处的前一个值,在本例中为 10。

然后,我们使用它Atomics.store()来存储特定的值,在本例中为 3,在数组的特定索引处,在本例中为 0,即第一个位置。
Atomics.store()将返回我们刚刚传递的值,在本例中为 3。您可以看到,当我们调用Atomics.load()该特定索引时,我们得到的是 3,而不是 5。

Atomics.and()Atomics.or()Atomics.xor()

这三种方法均在数组的给定位置执行按位与、或和异或运算。您可以在维基百科的链接https://en.wikipedia.org/wiki/Bitwise_operation上了解有关位运算的更多信息。

ES2017 Async 和 Await

继续阅读...或者只是获取备忘单


非常感谢你的阅读。欢迎在DevTo、博客inspiredwebdevTwitter上关注我。

免责声明:亚马逊和 Educative 的链接为联盟链接,您的购买将为我带来额外佣金。谢谢


书籍横幅

在AmazonLeanpub上获取我的电子书

文章来源:https://dev.to/albertomontalesi/javascript-everything-from-es2016-to-es2019-246c
PREV
如何在10分钟内丢掉工作
NEXT
程序员必备的 5 款最佳免费笔记应用