JavaScript – Rest Parameters & Spread Operator
介绍
Rest 和 Spread 的共同点是语法都是 ... (点点点). 但它们的概念是相反的. 看例子体会:
Rest Parameters
参考: 阮一峰 – rest 参数
rest parameters 可以替代 arguments 对象.
old school:
function method(v1, v2, v3) { console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); console.log(arguments[3]); // 4 console.log(arguments.length); // 4 console.log(Array.isArray(arguments)); // false // arguments is iterable for (const arg of arguments) { console.log('arg', arg); } } method(1, 2, 3, 4);
modern:
function method(...args) { console.log(Array.isArray(args)); // true } method(1, 2, 3, 4);
除了它是 array 以外, 其它都和 arguments 一样,
left arguments
除了可以取代 arguments 对象, 它还可以更灵活.
function method(firstArg, ...leftArgs) { console.log(firstArg); // 1 console.log(leftArgs); // [2, 3, 4] } method(1, 2, 3, 4);
直接把 arguments 拆成 2 组, 是不是很方便?
注: rest parameters 只能放到最后一个 parameter 哦, 下面这样放中间是不行的哦
use in destructuring assignment
const [v1, ...others] = [1, 2, 3, 4];
和 left arguments 同个概念, 只是用在 destructuring assignment 上. (rest 依然必须在最后一个哦)
解构对象也是可以的
const { name, ...leftProperties } = { name: 'Derrick', age: 11 }; console.log(leftProperties.age); // 11
Spread Operator
参考:
spread operator 可以用在 array 和 object 上, 先看看 array 的用法.
spread array to parameters
function method(a, b, c) {} method(1, 2, 3); method(...[1, 2, 3]); method(1, ...[2, 3]);
rest parameters 是把多个值 combine 到一个 array 里. spread operator 有点相反的味道.
它把一个 array 拆成多个 parameters 输入.
spread array fill into array
const array1 = [1, 2, 3]; const array2 = [...array1, 4, 5]; // [1, 2, 3, 4, 5]
array1 被拆成一个一个放入新的 array 中.
如果 array 是空的, 那什么也不会发生.
const array3 = [...[], 4, 5]; // [4, 5]
spread object fill into object
这个是 ES2018 才有哦.
和 fill into array 玩法一样
const obj1 = { age: 11 }; const obj2 = { name: 'Derrick', age: 10, ...obj1, level: 50, }; // obj2 = { name: 'Derrick', age: 11, level: 50 }
obj1.age 11 覆盖掉了原本的 obj2.age 10, 上面这个写法和 Object.assign 是等价的哦.
小心 undefined
const obj1 = { name: undefined, }; const obj2 = { name: 'Derrick', ...obj1, }; console.log(obj2.name); // undefined
Object.assign 也会这样哦. 所以要特别小心. 有 2 个解决方法:
第一是针对属性做判断
const obj1 = { name: undefined, }; const obj2 = { name: 'Derrick', ...(obj1.name !== undefined ? { name: obj1.name } : undefined), }; console.log(obj2.name); // 'Derrick'
当 obj1.name 有值就变成 ...{ name: obj1.name } 不然就是 ...undefined, 然后 undefined 会被强转成 empty object 最终就是 ...{} 啥也没有就抵消掉了.
另一个方法是自己封装一个 Object.Assign, 自己 loop key 检查是否是 own property 才 override.
总结
Rest Parameters 像 "收", 把多个值收集到一个 array 或 object 中.
Spread Operator 像 "放" 把 array 或 object 里的值, 释放开来.
可以同时 "放" 多个, 但是不能 "收" 多个.
const a = [1, 2]; const b = [4, 5]; const c = [...a, 3, ...b]; // 同时释放 2 个 const [...a, 3, ...b] = [1, 2, 3, 4, 5]; // error! 同时收 2 个是不可以的 (因为它不知道要 combine 多少个丫)