Over the last few years, JavaScript has seen massive improvements to its syntax and functionality with the addition of a bunch new features.
在过去的几年中,JavaScript有了许多新功能,从而对其语法和功能进行了重大改进。
One of the most useful of those new features is the spread operator (aka the … operator)
这些新功能中最有用的功能之一是点差运算符(也称为…运算符)
Spread is super helpful, but its syntax is not particularly meaningful upon first glance. It doesn’t tell you much as to what it does. Fortunately, once you learn the three main uses for Spread, it will become one of your favourite tools in the JS toolbox!
传播超级有帮助,但是乍一看它的语法没有特别的意义。 它并不能告诉您有关它的功能。 幸运的是,一旦您了解了Spread的三个主要用途,它将成为JS工具箱中您最喜欢的工具之一!
According to MDN: “Spread syntax allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.”
根据MDN: “使用扩展语法,可以在需要零个或多个参数(用于函数调用)或元素(用于数组文字)或对象表达式在以下位置扩展的地方扩展数组表达式或字符串之类的可迭代对象。期望零个或多个键值对(用于对象文字)的地方。”
There are three places you can use spread:
您可以在三个地方使用传播:
- Function calls 函数调用
- Array literals 数组文字
- Object literals 对象文字
传播与功能 (Spread & Functions)
When passing arguments to a function, We can use spread to expand an iterable element. Rather than having to pass each argument individually, We can “Spread” out each item as its argument.
将参数传递给函数时,我们可以使用spread扩展可迭代的元素。 不必单独传递每个参数,我们可以“扩展”每个项目作为其参数。
Math.min
is a function which accepts any number of arguments and returns the minimum value. If we wanted to find the minimum value of an array, It doesn't work to pass the entire array in:
Math.min
是一个接受任意数量的参数并返回最小值的函数。 如果我们想找到一个数组的最小值,则无法将整个数组传递给:
const temperatures = [76,72,68,79,54,65];Math.min(temperatures)//Result
▶ NaN
Instead, we can use spread to expand our array, Passing in each element as an argument:
相反,我们可以使用spread扩展数组,将每个元素作为参数传递:
const temperatures = [76,72,68,79,54,65];
Math.min(...temperatures)
//the same as Math.min(76,72,68,79,54,65)//Result
▶ 54
Here’s one more example of using console.log
. If we pass an entire array to console.log
这是使用console.log
的另一个示例。 如果我们将整个数组传递给console.log
const tvShows = ["Six Feet Under", "Chernobyl", "Black Mirror", "Fleabag" ]
console.log(tvShows);
This is what we see:
这是我们看到的:
▶(4) ["Six Feet Under", "Chernobyl", "Black Mirror", "Fleabag"]
The entire array is treated as one argument. If we instead use Spread, we end up passing four arguments to console.log
整个数组被视为一个参数。 如果改为使用Spread,则最终将四个参数传递给console.log
const tvShows = ["Six Feet Under", "Chernobyl", "Black Mirror", "Fleabag" ]//I can pass each element in tvShows as a separate argument using spread: console.log(...tvShows);▶ Six Feet Under Chernobyl Black Mirror Fleabag
扩展和数组文字 (Spread & Array Literals)
组合阵列 (Combining Arrays)
We can also use spread syntax to create new arrays using existing arrays. For example, to combine two arrays, we could do this:
我们还可以使用扩展语法使用现有数组创建新数组。 例如,要合并两个数组,我们可以这样做:
const parents = ["Lorie", "John"];
const kids = ["Jackson", "Ana", "Jessy"];
const fullFamily = [...parents, ...kids];▶ //["Lorie", "John", "Jackson", "Ana", "Jessy"]
We can use spread as many times as we want in a given expression.
在给定的表达式中,我们可以根据需要使用任意多次。
const parents = ["Lorie", "John"];
const kids = ["Jackson", "Ana", "Jessy"];
const dogs = ["Olie", "Cosmo"];
const fullFamily = [...parents, ...kids, "Me", ...dogs, "Unnamed Turtle"];▶ //["Lorie", "John", "Jackson", "Ana", "Jessy", "Me", "Olie", "Cosmo", "Unnamed Turtle"]
复制阵列 (Copying An Array)
Spread is also commonly used to create a copy of an array.
Spread通常也用于创建数组的副本。
const originals = ["Mona Lisa", "American Gothic", "The School of Athens"];
const copies = [...originals];
originals.push("Nighthawks");
console.log(copies);▶ ["Mona Lisa", "American Gothic", "The School of Athens"]
Important Note: Spread only goes “one level” deep when copying an array. It does not perform a deep copy of nested arrays!
重要说明:复制阵列时,扩展仅深入“一级”。 它不会执行嵌套数组的深层复制!
传播和对象文字 (Spread & Object Literals)
Just like with arrays, We can use spread to combine existing objects:
就像数组一样,我们可以使用传播来组合现有对象:
We can do the same thing for objects, and We can take existing objects and copy their properties over to new objects.
我们可以对对象执行相同的操作,并且可以获取现有对象并将其属性复制到新对象上。
const lion = {hasTail: true, legs: 4};
const eagle = {canFly: true };
const hybrid = {name: "Gryphon", ...lion, ...eagle};▶//{name: "Gryphon", hasTail: true, legs: 4, canFly: true}
价差和不变性 (Spread & Immutability)
Now there’s one last topic here, That’s really important which has to do with why you should care about this and I’m going to use the example of React.
现在这里有最后一个主题,那真的很重要,这与您为什么要关心这一点有关,我将使用React的示例。
In frameworks like React, It’s important not to mutate specific data (the state, specifically). Because of the way React is written, updating arrays & objects directly in the state can cause issues where your app does not render or re-render when it should. You’ll often see Spread used in this context.
在像React这样的框架中,重要的是不要突变特定的数据(特别是状态)。 由于React的编写方式,直接在状态中更新数组和对象可能会导致问题,导致您的应用在应有的状态下无法呈现或重新呈现。 您经常会看到在这种情况下使用了Spread。
Here’s a simple example of what NOT to do. We have an array of todos
and we want to add a new todo to the end of that array. The "easy" way is to simply push on to todos
BUT THAT MUTATES THE ARRAY!
这是不做什么的简单示例。 我们有一个数组todos
,我们希望新的待办事项添加到该数组的末尾。 “易”的方法是简单地推到todos
但变种的数组!
const todos = [
{user: "Brick", completed: false, task: "Upload Video"},
{user: "Lilith", completed: true, task: "Rob Bank"}
]function addTodo(newTodo){
todos.push(newTodo);
}
Here we have a function called addTodo
this is the very naive addTodo
. Where we have an array of todos
. Each one is an object you'd think the easiest way to add a new to do is to push on to the todos
and this works! There's no problem with this on its own, but if this was written for React or a similar framework where we don't want to mutate our data structure.
在这里,我们有一个名为addTodo
的函数,这是非常幼稚的addTodo
。 我们有很多todos
。 每一个对象,你会觉得最简单的方法来添加一个新做的是推到todos
和这个作品! 它本身没有问题,但是如果它是为React或类似框架编写的,我们不想改变我们的数据结构。
Rather than mutating the todos
array directly, We should instead make a copy of the todos
array that also contains the newTodo
added at the end. Spread makes this relatively easy:
而不是突变的todos
直接阵性,我们应该做的副本todos
阵列还包含newTodo
加末。 传播使这相对容易:
const todos = [
{user: "Brick", completed: false, task: "Upload Video"},
{user: "Lilith", completed: true, task: "Rob Bank"}
]function addTodo(newTodo){
return [...todos, {...newTodo, completed: false}]
}const newTodos = addTodo({user: "Mordecai", task: "Feed Bloodwing"});
We could do something like this instead, So we have the same array called todos
but this time the addTodo
a function is a little bit different. It returns an array where we spread all the existing todos
to in this case. And then at the end of that array, we add in a new object.
我们可以做这样的事情,所以我们有一个叫做todos
数组,但是这次addTodo
函数有点不同。 它返回一个数组,在这种情况下,我们将所有现有todos
扩展到该数组。 然后在该数组的末尾,添加一个新对象。
So now if I call addTodo
and I pass an object.
所以现在如果我调用addTodo
并传递了一个对象。
You’ll notice todos
itself has not been updated. I didn't mutate todos
您会发现todos
本身尚未更新。 我没有变异todos
What we did instead made a new array.
相反,我们做了一个新的数组。
That’s it! Hope you enjoyed this article and it helps you in development.You can read my other articles too.
而已! 希望您喜欢这篇文章,对您的开发有所帮助。您也可以阅读我的其他文章。
Keep Learning! Happy Coding 👩💻
保持学习! 快乐编码👩👩
翻译自: https://medium.com/javascript-in-plain-english/why-i-love-the-spread-operator-58f396dbbb78