rest参数和扩展运算符都是ES6
新增的特性。
rest参数的形式为:...变量名
;扩展运算符是三个点(...
)。
rest参数
rest参数用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
1 2 3 4 5 6 7 8 9
| function add(...values) { let sum = 0; for (var val of values) { sum += val; } return sum; } add(1, 2, 3) // 6
|
传递给 add 函数的一组参数值,被整合成了数组 values。
下面是一个 rest 参数代替arguments变量的例子。
1 2 3 4 5 6 7
| // arguments变量的写法 function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); } // rest参数的写法 const sortNumbers = (...numbers) => numbers.sort();
|
rest参数和arguments对象的区别
- rest参数只包含那些没有对应形参的实参;而 arguments 对象包含了传给函数的所有实参。
- arguments 对象不是一个真实的数组;而rest参数是真实的 Array 实例,也就是说你能够在它上面直接使用所有的数组方法。
- arguments 对象对象还有一些附加的属性 (比如callee属性)。
另外,使用rest参数时应注意一下两点:
- rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
1
| function f(a, ...b, c) { ... } // 报错
|
1 2 3
| (function(a) {}).length // 1 (function(...a) {}).length // 0 (function(a, ...b) {}).length // 1
|
扩展运算符
扩展运算符可以看做是 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
1 2 3
| console.log(...[1, 2, 3]) // 1 2 3 console.log(1, ...[2, 3, 4], 5) //1 2 3 4 5
|
扩展运算符的应用
普通的函数调用
1 2 3 4 5 6 7 8 9 10
| function push(array, ...items) { array.push(...items); } function add(x, y) { return x + y; } var numbers = [4, 38]; add(...numbers) // 42
|
上面代码中,array.push(...items)
和add(...numbers)
这两行,都是函数的调用,它们的都使用了扩展运算符。该运算符将一个数组,变为参数序列。
替代 apply 方法调用函数
1 2 3 4 5 6 7 8
| // ES5 的写法 Math.max.apply(null, [14, 3, 77]) // ES6 的写法 Math.max(...[14, 3, 77]) // 等同于 Math.max(14, 3, 77);
|
1 2 3 4 5 6 7 8 9
| // ES5 的写法 var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; Array.prototype.push.apply(arr1, arr2); // ES6 的写法 var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; arr1.push(...arr2);
|
合并数组
1 2 3 4 5 6 7 8 9
| var arr1 = ['a', 'b']; var arr2 = ['c']; var arr3 = ['d', 'e']; // ES5的合并数组 arr1.concat(arr2, arr3) // [ 'a', 'b', 'c', 'd', 'e' ] // ES6的合并数组 [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ]
|
与解构赋值结合
1 2 3 4 5 6 7 8 9 10 11
| const [first, ...rest] = [1, 2, 3, 4, 5]; first // 1 rest // [2, 3, 4, 5] const [first, ...rest] = []; first // undefined rest // [] const [first, ...rest] = ["foo"]; first // "foo" rest // []
|
如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
1 2 3
| const [...butLast, last] = [1, 2, 3, 4, 5]; // 报错 const [first, ...middle, last] = [1, 2, 3, 4, 5]; // 报错
|
将字符串转为数组
1 2 3 4 5 6 7
| var str = 'hello'; // ES5 var arr1 = str.split(''); // [ "h", "e", "l", "l", "o" ] // ES6 var arr2 = [...str]; // [ "h", "e", "l", "l", "o" ]
|
实现了 Iterator 接口的对象
任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组。
1 2
| var nodeList = document.querySelectorAll('div'); var array = [...nodeList];
|
上面代码中,querySelectorAll
方法返回的是一个nodeList
对象。它不是数组,而是一个类似数组的对象。这时,扩展运算符可以将其转为真正的数组,原因就在于NodeList
对象实现了 Iterator
。
总结
从上面的例子可以看出,rest参数使用场景应该稍少一些,主要是处理不定数量参数,可以避免arguments对象的使用。而扩展运算符的应用就比较广了,在实际项目中灵活应用,能写出更精简的代码。