JavaScript 中的扩展运算符与其余运算符
内容:
让我们来学习如何在代码中使用三个点。读完这篇文章,你就不会忘记它们之间的区别了!🐱🐱🐱
定义:
-
展开运算符可以将可迭代对象展开成单个元素。
-
其余部分是我们用来表示数组中不确定数量的参数的运算符。
两者都用三个点表示...,但你会发现很容易区分展开和休息!最后,还有一个小技巧要分享给你!
价差操作商
连接数组
展开运算符允许我们合并两个或多个数组,从而保持语言的简洁清晰。
一起喝杯咖啡吧?☕️ 请看下面的两个数组:
const coffee = ['coffee', 'water'];
const spices = ['cinnamon', 'nutmeg', 'cardamom'];
我们可以使用展开式将各种成分混合成一个数组:
const coffeeReady = [...coffee, ...spices];
console.log(coffeeReady)
// output:
// ['coffee', 'water', 'cinnamon', 'nutmeg', 'cardamom'];
简单!比逐个从两个数组中写入元素来形成要好得多coffeeReady。
重要的:
1. 更改coffee不会影响coffeeReady!
为了更好地理解:当我们进行复制时,我们可以创建一个指向原始值的新引用,或者直接复制该值。创建新引用实际上就是创建一个变量,该变量指向内存中原始值所在的同一位置。
如果我们创建了一个新的引用,那么对现有数组的任何更改coffee都会影响到现有数组coffeeReady,反之亦然。但我们使用展开运算符(spread)所做的只是复制值,该值随后会存储在内存中的另一个位置。因此,对一个数组的更改不会影响另一个数组。
然而,一些细节可能会改变这种局面!这是因为……
2. 这种传播方式只能制造肤浅的复制品!
这意味着,根据数组 `a` 中包含的数据coffee,某些更改确实会影响`b` coffeeReady!如果coffee`a` 包含非原始值,计算机就会在内存中创建一个指向这些值的引用。因此,对其中一个数组的任何更改都会影响另一个数组,因为它们都存储了对内存中同一位置的引用。请参见下文:
let a = [1, [2, 3]];
// [2, 3] is an array nested in a, and therefore
// it is a non-primitive value
const b = [4, 5, 6];
let c = [...a, ...b];
console.log(c);
// output: [1, [2, 3], 4, 5, 6]
a[0] = 11;
a[1][0] = 22;
console.log(c);
// output: [1, [22, 3], 4, 5, 6]
如上所示,更改 `a`a[0]并未影响 `b` c,因为我们更改的是一个原始值。换句话说,` a[0]a` 和`b`c指向相同的值,但它们位于内存中的不同位置。然而,更改`b` 会a[1][0]改变 `c` ,因为我们更改了 `a`和`b` 都指向c的那个值。a[1][0]c
合并对象
我们还可以使用展开运算符将对象合并为一个对象:
const myParents = {
fathersName: 'Michael',
mothersName: 'Louise'
};
const mySiblings = {
brothersName: 'Philip',
sistersName: 'Lara'
};
const myFamily = { ...myParents, ...mySiblings };
console.log(myFamily);
/* output:
{
fathersName: 'Michael',
mothersName: 'Louise',
brothersName: 'Philip',
sistersName: 'Lara'
}
*/
但是,需要注意的是,这种展开式并不会复制完全相同的属性!下面我们有两个对象,它们的属性分别为brothersName:
const myParents = {
fathersName: 'Michael',
mothersName: 'Louise',
brothersName: 'Gabriel'
};
const mySiblings = {
brothersName: 'Philip',
sistersName: 'Lara'
};
const myFamily = { ...myParents, ...mySiblings };
console.log(myFamily);
/* output:
{
fathersName: 'Michael',
mothersName: 'Louise',
brothersName: 'Philip',
sistersName: 'Lara'
}
*/
请注意,最终对象不会同时继承两个brothersName键。实际上,只会保留其中一个键,即来自第二个对象的键。
复制数组和对象
明白了吗?如果我们能合并数组和对象,那就意味着我们也能分别复制它们:
// creating a shallow copy of coffee:
const coffee = ['coffee', 'water'];
const coffeeCopy = [...coffee];
console.log(coffeeCopy)
// output:
// ['coffee', 'water'];
// creating a shallow copy of mySiblings:
const mySiblings = {
brothersName: 'Philip',
sistersName: 'Lara'
};
const myFamily = {
fathersName: 'Michael',
mothersName: 'Louise',
...mySiblings
};
// Now we can treat brothersName and sistersName as
// a property of myFamily:
console.log(myFamily.brothersName)
// output: Philip
将字符串转换为数组
也可以使用扩展运算符将字符串转换为数组。这使得我们在操作字符串时更加灵活,因为我们可以将数组方法应用于字符串:
const str = 'coffee';
const letters = [...str, 's.', '☕️'];
console.log(letters);// ["c", "o", "f", "f", "e", "e", "s.", "☕️"]
剩余运算符
如上所述,剩余运算符用于将元素打包到数组中。你会发现,在处理大量值或值的数量不确定时,剩余运算符是一个非常有用的工具。
函数参数
剩余运算符允许我们将不定数量的参数表示为数组。
const order = function(beverage, ...otherIngredients) {
console.log(beverage);
console.log(otherIngredients);
};
order('green tea', 'milk', 'brown sugar');
// output:
// green tea
// ['milk', 'brown sugar']
请注意,这允许我们使用更多参数调用同一个函数,因为剩余运算符会将所有参数放入otherIngredients数组中:
const order = function(beverage, ...otherIngredients) {
console.log(beverage);
console.log(otherIngredients);
};
order('green tea', 'milk', 'brown sugar', 'mint', 'tonka');
// output:
// green tea
// ['milk', 'brown sugar', 'mint', 'tonka']
🍵 一个重要的细节是,剩余部分必须是函数中的最后一个参数function(...otherIngredients, beverage)!如果我们这样写,计算机就不知道何时停止,这段代码就会出错。
以休息和传播的方式进行解构
剩余元素和展开运算符也广泛用于解构赋值。如果您还不了解解构赋值,我建议您阅读我的另外两篇文章:数组解构和对象解构。
使用剩余部分:
const [a, b, ...others] = [1, 2, 3, 4, 5];
console.log(a, b, others);
// output: 1 2 [3, 4, 5]
现在,记住这个技巧,这样你就不会把“剩余部分”和“展开部分”混淆了:剩余部分在左边, “展开部分”=在右边=。
休息时间 = ☕️
🍵 = ...传播
感谢你读到这里!希望这篇文章对你有所帮助!有什么想法吗?请在下方留言!
文章来源:https://dev.to/baroblesvi/spread-vs-rest-operators-in-javascript-45f3