这篇文章主要记录和学习Rest parameters和Spread Operator的区别和联系。今天我去了解了下关于Rest解构赋值/扩展运算符的用法和区别。主要是开始的时候容易弄混淆。所以想要记录和学习下来。也分享给大家。
Peview
if you don’t use rest parameter
Aggregation of remaining arguments into single parameter of variadic functions.
1 | function f(x, y) { |
如果使用Rest Parameter就会简单很多:
1 | function f(x, y, ...a){ |
If you don’t use spread operator
Spreading of elements of an iterable collection (like an array or even a string) into both literal elements and individual function parameters.
1 | var params = ["hello", true, 7]; |
如果使用spread operator的话:1
2
3
4
5
6var params = ["hello", true, 7];
var extends = [1, 3, ...params];
f(1,3, ...params);
var str = "Seven";
var chars = [...str]; //["S", "e", "v", "e", "n"]
下面具体看下两种新的 Extended Parameter Handling。
Rest parameters
The rest parameter syntax allows us to represent an indefinite number of arguments as an array.
在ES6的新特性中,Rest parameters可以为我们带来很多方便的地方。它可以帮助我们去把一系列不确定个数的参数转换成数组。
Rest parameters的语法
1 | function(a, b, ...theArgs) { |
比如我们传入 fun(1,2,3,4),那么a将为1,b将为2,theArgs将为[3,4]。
arguments和rest parameters的区别
区别主要有下面三点:
rest parameters are only the ones that haven’t been given a separate name, while the arguments object contains all arguments passed to the function;
the arguments object is not a real array, while rest parameters are Array instances, meaning methods like sort, map, forEach or pop can be applied on it directly;
the arguments object has additional functionality specific to itself (like the callee property).
-FROM MDN => rest_parameters
我觉得讲的很清楚了。具体怎么使用,我们看下面的几个例子来更好的理解这些区别。
煮几个栗子
1 | function sum() { |
上面是我们最长看到的一个相加参数的方法。由于arguments不是数组,所以我们在使用前要先将他转换成数组。我们再看看rest的写法。1
2
3
4
5
6
7
8
9function sum(…numbers) {
var result = 0;
numbers.forEach(function (number) {
result += number;
});
return result;
}
console.log(sum(1)); // 1
console.log(sum(1, 2, 3, 4, 5)); // 15
由于使用…numbers的参数就已经是被转换成数组了,所以我们可以直接使用。
再看个几个可以直接使用rest的例子。1
2
3
4
5
6
7
8function multiply(multiplier, ...theArgs) {
return theArgs.map(function (element) {
return multiplier * element;
});
}
var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
上面看两个地方,第一是传参数是从第二个开始传的。1
2
3
4
5
6
7
8
9
10
11
12
13
14function sortRestArgs(...theArgs) {
var sortedArgs = theArgs.sort();
return sortedArgs;
}
console.log(sortRestArgs(5,3,7,1)); // shows 1,3,5,7
function sortArguments() {
var sortedArgs = arguments.sort();
return sortedArgs; // this will never happen
}
// throws a TypeError: arguments.sort is not a function
console.log(sortArguments(5,3,7,1));
再举一个经常见到的例子:1
2
3
4
5function logArguments() {
for (var i=0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
下面是更好的一种写法:1
2
3
4
5function logArguments(...args) {
for (let arg of args) {
console.log(arg);
}
}
好,到目前为止,你肯定很清楚,不过估计过一会可能会混淆了,就像我一样。下面我们看看spread。
Spread_operator
spread的基本语法
用于函数调用:1
myFunction(...iterableObj);
用于数组字面量:1
[...iterableObj, 4, 5, 6]
也就是说spread有两种情况。一个是在函数中使用的情况。一个是在数组字面量的情况。在函数中就相当于是分割成单个参数,在数组中是组成一个更大的数组。
spread和rest parameter的区别
spread和rest parameters非常像。因为它们都有…这个表达式。但是它们几乎是相反的操作。spread 可以把一个数组分割成单个的参数。然后传递给函数。而刚刚我们讲的rest则是把单个的参数转换成数组传递下去。
还有一种操作符叫做剩余操作符(the rest operator),它的样子看起来和展开操作符一样,但是它是用于解构数组和对象。在某种程度上,剩余元素和展开元素相反,展开元素会“展开”数组变成多个元素,剩余元素会收集多个元素和“压缩”成一个单一的元素。
1 | function sum(a, b, c) { |
但是在ES5中我们一般是这么做的:1
2
3
4
5function sum(a, b, c) {
return a + b + c;
}
var args = [1, 2, 3];
console.log(sum.apply(undefined, args)); // 6
因为apply可以帮助我们把数组变成单个的参数。这样是不是很方便了。1
2
3
4
5function sum(a, b, c) {
return a + b + c;
}
var args = [1, 2];
console.log(sum(…args, 3)); // 6
也可以像上面一样混淆着写。所以我们总结下。
更好的apply
我们都是使用Function.prototype.apply方法来将一个数组展开成多个参数:1
2
3function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);
用了展开符我们可以这样写:1
2
3function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);
也可以展开多个:1
2
3function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
更强大的数组字面量
如果在已有的数组中的某个部分添加一个属性,通常会用到push,splice,concat 等数组方法。有了扩展运算符会让代码更简洁:1
2var parts = ['shoulder', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes']; // ["head", "shoulders", "knees", "and", "toes"]
更好的 push 方法
1 | var arr1 = [0, 1, 2]; |
上面是我们一般将数组push添加到一个数组的情况。下面是我们使用spread操作符。1
2
3var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);
将类数组对象转换成数组
1 | var nodeList = document.querySelectorAll('div'); |
举几个很常用的例子
如果我们有一个数组,要求它的最大值,通常我们会这么做:1
2
3var myArr = [5,3,9];
Math.max(myArr); // NaN
Math.max.apply(Math,myArr); // 9
一般我们都是利用apply可以把数组转换为单个参数。现在我们可以这样做:1
2var myArr = [5,3,9];
Math.max(...myArr); //9
是不是很方便?还有一个优点:扩展运算符支持构造函数:1
2
3new Date(...[2016, 5, 6]);
new Date.apply(null, [2016, 8, 2]); // TypeError: Date.apply is not a constructor
new (Function.prototype.bind.apply(Date, [null].concat([2016, 8, 2]))); //Date 2016-09-01T16:00:00.000Z
总结
主要是了解了ES6的这两个新特性。我觉得很好用。不过都是要刻意的去用才有熟悉的过程。否则估计过不了多久就忘记啦。大部分整理和学习自MDN。感谢。MDN - Spread_operator