11

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

 3 years ago
source link: https://titangene.github.io/article/javascript-object-rest-spread-properties.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
javascript.jpg

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

本文同步發表於 iT 邦幫忙:JavaScript 之旅 (13):Object Rest/Spread Properties

「JavaScript 之旅」系列文章發文於:

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

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

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

Rest Properties

rest properties 會收集剩餘的 own enumerable property keys,這些 key 都未被解構 pattern 選取。這些 key 和值會複製至新的物件上:

1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
2
3
let data = null;
let { x, y, ...z } = data;
// TypeError: Cannot destructure property 'x' of 'null' as it is null.

解決方法就是給初始值,初始值為空物件:

1
2
3
4
5
6
7
8
9
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

1
2
let { ...x, y, z } = {};
// SyntaxError: Rest element must be last element

並且只能有一個 rest property:

1
2
let { x, ...y, ...z } = {};
// SyntaxError: Rest element must be last element

clone 物件

1
2
3
4
5
6
7
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:

1
2
3
4
5
6
7
8
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}
1
2
3
4
5
6
7
8
9
10
11
12
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

重新組合物件

1
2
3
4
5
6
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 從提供的物件複製到新建立的物件:

1
2
3
4
5
6
7
8
9
10
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 會被忽略:

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

clone 物件

1
2
3
4
5
6
7
let post = {id: 1, title: 'xxx'};
let clonedPost = {...post};

console.log(clonedPost);
// {id: 1, title: "xxx"}
console.log(post === clonedPost);
// false

過去可能會用 Object.assign()

1
2
3
4
5
6
7
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

1
2
3
4
5
6
let initUser = {name: '', age: null};
let updateUser = {name: 'Titan'};
let user = {...initUser, ...updateUser};

console.log(user);
// {name: "Titan", age: null}

過去可能會用 Object.assign()

1
2
3
4
5
6
let initUser = {name: '', age: null};
let updateUser = {name: 'Titan'};
let user = Object.assign({}, initUser, updateUser);

console.log(user);
// {name: "Titan", age: null}

合併 property

1
2
3
4
5
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()

1
2
3
4
5
6
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"}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK