本篇介紹 ES2018 (ES9) 提供的 object rest/spread properties。
在 ES6 時,引入了以下特性:
而此 提案 是在 ES2018 (ES9) 引入了以下特性:
rest properties 會收集剩餘的 own enumerable property keys,這些 key 都未被解構 pattern 選取。這些 key 和值會複製至新的物件上:
let { id, name, ...otherProps } = {
id: 1,
name: 'Titan',
sex: 'Male',
age: 18
};
console.log(id);
// 1
console.log(name);
// Titan
console.log(otherProps);
// {sex: "Male", age: 18}
有些情況下會報錯,例如:
不能解構賦值 null
,否則會出現 TypeError
:
let data = null;
let { x, y, ...z } = data;
// TypeError: Cannot destructure property 'x' of 'null' as it is null.
解決方法就是給初始值,初始值為空物件:
let data = null ?? {};
let { x, y, ...z } = data;
console.log(x);
// undefined
console.log(y);
// undefined
console.log(z);
// undefined
rest property 一定要放在最後一個,否則會出現 SyntaxError
:
let { ...x, y, z } = {};
// SyntaxError: Rest element must be last element
並且只能有一個 rest property:
let { x, ...y, ...z } = {};
// SyntaxError: Rest element must be last element
let post = {id: 1, title: 'xxx'};
let { ...clonedPost } = post;
console.log(clonedPost);
// {id: 1, title: "xxx"}
console.log(post === clonedPost);
// false
但不包含 prototype,只會複製 own enumerable property:
let post = {id: 1, title: 'xxx'};
let extendedPost = Object.create(post);
extendedPost.likeCount = 666;
extendedPost.shareCount = 99;
let { ...clonedPost } = extendedPost;
console.log(clonedPost);
// {likeCount: 666, shareCount: 99}
let post = {
emoji: { like: 1, love: 2, wow: 3, haha: 4 },
};
let {
emoji: { like: likeCount, ...otherEmojis },
} = post;
console.log(likeCount);
// 1
console.log(otherEmojis);
// {love: 2, wow: 3, haha: 4}
function baseFunc({ a, b }) {
console.log(`a: ${a}`);
console.log(`b: ${b}`);
}
function wrapperFunc({ x, y, ...restConfig }) {
console.log(`x: ${x}`);
console.log(`y: ${y}`);
console.log(restConfig);
return baseFunc(restConfig);
}
wrapperFunc({a: 1, b: 2, x: 4, y: 5});
// x: 4
// y: 5
// {a: 1, b: 2}
// a: 1
// b: 2
let assembled = { x: 1, y: 2, a: 3, b: 4 };
let { x, y, ...z } = assembled;
let reassembled = { x, ...z };
console.log(reassembled);
// {x: 1, a: 3, b: 4}
物件 initializer 中的 spread properties 會將 own enumerable properties 從提供的物件複製到新建立的物件:
let id = 1;
let name = 'Titan';
let otherProps = {
sex: 'Male',
age: 18
}
let person = { id, name, ...otherProps };
console.log(person);
// {id: 1, name: "Titan", sex: "Male", age: 18}
若值為 null
或 undefined
會被忽略:
let emptyObject = { ...null, ...undefined };
console.log(emptyObject);
// {}
let post = {id: 1, title: 'xxx'};
let clonedPost = {...post};
console.log(clonedPost);
// {id: 1, title: "xxx"}
console.log(post === clonedPost);
// false
過去可能會用 Object.assign()
:
let post = {id: 1, title: 'xxx'};
let clonedPost = Object.assign({}, post);
console.log(clonedPost);
// {id: 1, title: "xxx"}
console.log(post === clonedPost);
// false
let initUser = {name: '', age: null};
let updateUser = {name: 'Titan'};
let user = {...initUser, ...updateUser};
console.log(user);
// {name: "Titan", age: null}
過去可能會用 Object.assign()
:
let initUser = {name: '', age: null};
let updateUser = {name: 'Titan'};
let user = Object.assign({}, initUser, updateUser);
console.log(user);
// {name: "Titan", age: null}
let date = {from: '2020-01-01', to: '2020-06-01'};
let activity = {id: 1, ...date};
console.log(activity);
// {id: 1, from: "2020-01-01", to: "2020-06-01"}
過去可能會用 Object.assign()
:
let date = {from: '2020-01-01', to: '2020-06-01'};
let id = 1;
let activity = Object.assign({}, {id}, date);
console.log(activity);
// {id: 1, from: "2020-01-01", to: "2020-06-01"}