JS: Object.assign() Vs Spread Operator

昨天写了一篇关于 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…

猜你喜欢

转载自juejin.im/post/5c372f856fb9a049b13e68ee