=
只能 Copy Object 的 Reference,而非真正 Clone Object,本文整理出 4 種方式,並詳細分析其特色。
Version
macOS Mojave 10.14.5
VS Code 1.37.0
Quokka 1.0.240
ECMAScript 2015
Ramda 0.26.1
Assignment Operator
import { equals } from 'ramda';
let obj1 = { name: 'Sam' };
let obj2 = obj1;
obj1 === obj2; // ?
equals(obj1, obj2); // ?
直覺會使用 =
assignment operator。
使用 ===
判斷為 true
,可見 obj1
與 obj2
的 reference 相同,因此為 copy reference,並非 clone object。
使用 Ramda 的 equals()
判斷為 true
,由於 obj1
與 obj2
的 reference 相同,value 當然相同。
Object.assign()
import { equals } from 'ramda';
let obj1 = { name: 'Sam' };
let obj2 = Object.assign({}, obj1);
obj1 === obj2; // ?
equals(obj1, obj2); // ?
在 ES5 若要 clone object,必須使用 Object.assign()
。
Object.assign(target, …sources)
將 source object merge 到 target object
target
:target object
...sources
:source object,可包含多個 object
Object.assign()
原本是 merge object,所以第一個 argument 為 target object,若 target object 為 {}
,其行為剛好等於 clone object。
JSON
import { equals } from 'ramda';
let obj1 = { name: 'Sam' };
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1 === obj2; // ?
equals(obj1, obj2); // ?
ES5 也可使用 JSON.stringify()
將 object 轉成 JSON string 後,再使用 JSON.parse()
轉成 object,由於這兩個 function 皆是 pure function,剛好實現了 clone object。
Spread Operator
import { equals } from 'ramda';
let obj1 = { name: 'Sam' };
let obj2 = { ...obj1 };
obj1 === obj2; // ?
equals(obj1, obj2); // ?
ES6 亦引進了 ...
spread operator,可將 object property 展開,若放在 {}
內,也能實現 clone object。
Ramda
import { clone } from 'ramda';
let obj1 = {
id: 1,
name: {
first: 'Sam',
last: 'Xiao'
}
};
let obj2 = {...obj1}; // ?
let obj3 = clone(obj1); // ?
obj2 === obj1; // ?
obj3 === obj1; // ?
obj1.name === obj2.name; // ?
obj1.name === obj3.name; // ?
無論是 Object.assign()
、 JSON.stringify() / JSON.parse()
或 spread operator,都只能對 object 做 shallow clone,第二層之後 object 為 copy reference。
obj1
的 name
包含 nested object,其中 obj2
使用 ...
,而 obj3
使用 Ramda 的 clone()
。
無論使用 ...
或 clone()
,obj2
與 obj3
的 reference 皆與 obj1
不同。
arr2.name
與obj1.name
的 reference 相同,顯然...
是 shallow clonearr3.name
與obj1.name
的 reference 不同,顯然clone()
deep clone
Conclusion
- 若要 shallow clone,則
...
spread operator 是可讀性最高寫法;若要 deep clone,則要使用 Ramda 的clone()
Reference
Samantha Ming, 3 Ways to Clone Objects in JavaScript
MDN, object.assign()
MDN, JSON.stringify()
MDN, JSON.parse()
Ramda, clone