iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 13
1
Modern Web

JavaScript 之旅系列 第 13

JavaScript 之旅 (13):Object Rest/Spread Properties

  • 分享至 

  • xImage
  •  

本篇介紹 ES2018 (ES9) 提供的 object rest/spread properties。

在 ES6 時,引入了以下特性:

而此 提案 是在 ES2018 (ES9) 引入了以下特性:

  • 用於物件解構賦值的 rest properties
  • 用於物件字面值的 spread properties

Rest Properties

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}

Error

有些情況下會報錯,例如:

Runtime Error

不能解構賦值 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

Static Error

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

clone 物件

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}

函數擴充額外的 option

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}

Spread Properties

物件 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}

若值為 nullundefined 會被忽略:

let emptyObject = { ...null, ...undefined };
console.log(emptyObject);
// {}

clone 物件

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

合併多個物件:預設 property 被更新值覆寫 property

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}

合併 property

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"}

資料來源


上一篇
JavaScript 之旅 (12):RegExp Lookbehind Assertions
下一篇
JavaScript 之旅 (14):Async Iterators
系列文
JavaScript 之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言