JS: Object.assign() Vs Spread Operator

FatGe發表於2019-01-10

昨天寫了一篇關於 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,而 setterundeined

    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
    }複製程式碼

    上述結果表明,在得到的 clone1clone2中,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
}
複製程式碼
參考

2ality.com/2016/10/res…

來源:https://juejin.im/post/5c372f856fb9a049b13e68ee

相關文章