= 只能 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