JS: Object.assign() Vs Spread Operator
阿新 • • 發佈:2019-01-11
昨天寫了一篇關於 Spread Operator 應用在 Object 上的博文,但是最後舉例 Object.assign()
與 ...
區別時,有些混淆,今天查了些資料,作為總結。
...
和 Object.assign()
整體的用法非常下關係,主要區別在於 Object.assign()
函式會觸發 setters,而 ...
語法則不會,也就是說 ...
是定義了新屬性,而 Object.assign()
則是設定了它們。
Object.assign()
的基本用法
-
改變原有物件
Object.assign(target, source1, source2); 複製程式碼
target
已經被修改,source1
以及source2
會被複制到其中。 -
建立新的物件
const result = Object.assign({}, source1, source2); 複製程式碼
result
是一個新的物件,source1
以及source2
被複制到其中。
在第二種方法上,...
與 Object.assign()
是非常類似的。接下來,闡述它們之間具體的相似點和不同點。
Object.assign
與 ...
的相同點
-
...
和Object.assign()
都是通過get
運算子來取值在將它們寫入目標之前,這兩個操作都會使用
get
getter
將轉換為正常的資料屬性,具體如下const original = { get foo() { console.log('getter'); return 123; } }; 複製程式碼
original
物件有getter foo
,而setter
為undeined
Object.getOwnPropertyDescriptor(original, 'foo') /* log { get: [Function: foo], set: undefined, enumerable: true, configurable: true } */
但是,利用
Object.assgin()
以及...
對original
物件進行克隆時,會發現const clone1 = {...original}; // 觸發 original 的 getter 會 log "getter" Object.getOwnPropertyDescriptor(clone1, 'foo'); /* log getter 以及被轉換為正常的資料屬性 { value: 123, writable: true, enumerable: true, configurable: true } */ const clone2 = Object.assign({}, original); // 觸發 original 的 getter 會 log "getter" Object.getOwnPropertyDescriptor(clone2, 'foo') { value: 123, writable: true, enumerable: true, configurable: true } 複製程式碼
上述結果表明,在得到的
clone1
和clone2
中,foo
只是一個普通的資料屬性(它的屬性描述符具有屬性值和可寫); -
...
和Object.assign
只會處理可列舉資料這兩個操作都會忽略所有繼承的屬性和所有不可列舉的屬性。
const proto = { inheritedEnumerable: 1, }; const obj = Object.create(proto, { ownEnumerable: { value: 2, enumerable: true, }, ownNonEnumerable: { value: 3, enumerable: false, }, }); console.log(obj); // { ownEnumerable: 2, ownNonEnumerable: 3, __proto__: { inheritedEnumerable: 1 } } console.log({ ...obj }); // { ownEnumerable: 2 } console.log(Object.assign({}, obj)); // { ownEnumerable: 2 } 複製程式碼
Object.assign
與 ...
的不同點
它們的不同點在於 ...
會定義屬性,而 Object.assign()
會設定它們,也就是說 ...
定義了目標物件中的新屬性,Object.assign()
則是使用 set
操作符進行寫入。
Object.defineProperty(Object.prototype, 'foo', {
set(value) {
console.log('SET', value);
},
});
const obj = {foo: 123};
console.log(Object.assign({}, obj));
// 會觸發 set, log SET 123
// log {}
console.log({ ...obj });
// log { foo: 123 }
複製程式碼