Object.assign()解释整理

链接:https://blog.csdn.net/wang252949/article/details/79106160

语法

Object.assign(target, ...sources)

参数

target
目标对象。
sources
源对象。

返回值

目标对象。

描述

如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性。

Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()Object.defineProperty() 。

String类型和 Symbol 类型的属性都会被拷贝。

在出现错误的情况下,例如,如果属性不可写,会引发TypeError,如果在引发错误之前添加了任何属性,则可以更改target对象。

注意,Object.assign 会跳过那些值为 null 或 undefined 的源对象。

示例

复制一个对象

  1.  
    var obj = { a : 1 } ;
  2.  
    var copy = Object . assign ( { } , obj ) ;
  3.  
    console . log (copy ) ; // { a: 1 }

深拷贝问题

针对深拷贝,需要使用其他方法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。

  1.  
    function test ( ) {
  2.  
    'use strict' ;
  3.  
     
  4.  
    let obj1 = { a : 0 , b : { c : 0 } } ;
  5.  
    let obj2 = Object . assign ( { } , obj1 ) ;
  6.  
    console . log ( JSON . stringify (obj2 ) ) ; // { a: 0, b: { c: 0}}
  7.  
     
  8.  
    obj1 .a = 1 ;
  9.  
    console . log ( JSON . stringify (obj1 ) ) ; // { a: 1, b: { c: 0}}
  10.  
    console . log ( JSON . stringify (obj2 ) ) ; // { a: 0, b: { c: 0}}
  11.  
     
  12.  
    obj2 .a = 2 ;
  13.  
    console . log ( JSON . stringify (obj1 ) ) ; // { a: 1, b: { c: 0}}
  14.  
    console . log ( JSON . stringify (obj2 ) ) ; // { a: 2, b: { c: 0}}
  15.  
     
  16.  
    obj2 .b .c = 3 ;
  17.  
    console . log ( JSON . stringify (obj1 ) ) ; // { a: 1, b: { c: 3}}
  18.  
    console . log ( JSON . stringify (obj2 ) ) ; // { a: 2, b: { c: 3}}
  19.  
     
  20.  
    // Deep Clone
  21.  
    obj1 = { a : 0 , b : { c : 0 } } ;
  22.  
    let obj3 = JSON . parse ( JSON . stringify (obj1 ) ) ;
  23.  
    obj1 .a = 4 ;
  24.  
    obj1 .b .c = 4 ;
  25.  
    console . log ( JSON . stringify (obj3 ) ) ; // { a: 0, b: { c: 0}}
  26.  
    }
  27.  
     
  28.  
    test ( ) ;

合并对象

  1.  
    var o1 = { a : 1 } ;
  2.  
    var o2 = { b : 2 } ;
  3.  
    var o3 = { c : 3 } ;
  4.  
     
  5.  
    var obj = Object . assign (o1 , o2 , o3 ) ;
  6.  
    console . log (obj ) ; // { a: 1, b: 2, c: 3 }
  7.  
    console . log (o1 ) ; // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

合并具有相同属性的对象

  1.  
    var o1 = { a : 1 , b : 1 , c : 1 } ;
  2.  
    var o2 = { b : 2 , c : 2 } ;
  3.  
    var o3 = { c : 3 } ;
  4.  
     
  5.  
    var obj = Object . assign ( { } , o1 , o2 , o3 ) ;
  6.  
    console . log (obj ) ; // { a: 1, b: 2, c: 3 }

属性被后续参数中具有相同属性的其他对象覆盖。

拷贝 symbol 类型的属性

  1.  
    var o1 = { a : 1 } ;
  2.  
    var o2 = { [ Symbol ( 'foo' ) ] : 2 } ;
  3.  
     
  4.  
    var obj = Object . assign ( { } , o1 , o2 ) ;
  5.  
    console . log (obj ) ; // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox)
  6.  
    Object . getOwnPropertySymbols (obj ) ; // [Symbol(foo)]

继承属性和不可枚举属性是不能拷贝的

  1.  
    var obj = Object . create ( { foo : 1 } , { // foo 是个继承属性。
  2.  
    bar : {
  3.  
    value : 2 // bar 是个不可枚举属性。
  4.  
    } ,
  5.  
    baz : {
  6.  
    value : 3 ,
  7.  
    enumerable : true // baz 是个自身可枚举属性。
  8.  
    }
  9.  
    } ) ;
  10.  
     
  11.  
    var copy = Object . assign ( { } , obj ) ;
  12.  
    console . log (copy ) ; // { baz: 3 }

原始类型会被包装为对象

  1.  
    var v1 = "abc" ;
  2.  
    var v2 = true ;
  3.  
    var v3 = 10 ;
  4.  
    var v4 = Symbol ( "foo" )
  5.  
     
  6.  
    var obj = Object . assign ( { } , v1 , null , v2 , undefined , v3 , v4 ) ;
  7.  
    // 原始类型会被包装,null 和 undefined 会被忽略。
  8.  
    // 注意,只有字符串的包装对象才可能有自身可枚举属性。
  9.  
    console . log (obj ) ; // { "0": "a", "1": "b", "2": "c" }

异常会打断后续拷贝任务

  1.  
    var target = Object . defineProperty ( { } , "foo" , {
  2.  
    value : 1 ,
  3.  
    writable : false
  4.  
    } ) ; // target 的 foo 属性是个只读属性。
  5.  
     
  6.  
    Object . assign (target , { bar : 2 } , { foo2 : 3 , foo : 3 , foo3 : 3 } , { baz : 4 } ) ;
  7.  
    // TypeError: "foo" is read-only
  8.  
    // 注意这个异常是在拷贝第二个源对象的第二个属性时发生的。
  9.  
     
  10.  
    console . log (target .bar ) ; // 2,说明第一个源对象拷贝成功了。
  11.  
    console . log (target .foo2 ) ; // 3,说明第二个源对象的第一个属性也拷贝成功了。
  12.  
    console . log (target .foo ) ; // 1,只读属性不能被覆盖,所以第二个源对象的第二个属性拷贝失败了。
  13.  
    console . log (target .foo3 ) ; // undefined,异常之后 assign 方法就退出了,第三个属性是不会被拷贝到的。
  14.  
    console . log (target .baz ) ; // undefined,第三个源对象更是不会被拷贝到的。

拷贝访问器

  1.  
    var obj = {
  2.  
    foo : 1 ,
  3.  
    get bar ( ) {
  4.  
    return 2 ;
  5.  
    }
  6.  
    } ;
  7.  
     
  8.  
    var copy = Object . assign ( { } , obj ) ;
  9.  
    // { foo: 1, bar: 2 }
  10.  
    // copy.bar的值来自obj.bar的getter函数的返回值
  11.  
    console . log (copy ) ;
  12.  
     
  13.  
    // 下面这个函数会拷贝所有自有属性的属性描述符
  14.  
    function completeAssign ( target , . . . sources ) {
  15.  
    sources . forEach ( source = > {
  16.  
    let descriptors = Object . keys (source ) . reduce ( ( descriptors , key ) = > {
  17.  
    descriptors [key ] = Object . getOwnPropertyDescriptor (source , key ) ;
  18.  
    return descriptors ;
  19.  
    } , { } ) ;
  20.  
     
  21.  
    // Object.assign 默认也会拷贝可枚举的Symbols
  22.  
    Object . getOwnPropertySymbols (source ) . forEach ( sym = > {
  23.  
    let descriptor = Object . getOwnPropertyDescriptor (source , sym ) ;
  24.  
    if (descriptor .enumerable ) {
  25.  
    descriptors [sym ] = descriptor ;
  26.  
    }
  27.  
    } ) ;
  28.  
    Object . defineProperties (target , descriptors ) ;
  29.  
    } ) ;
  30.  
    return target ;
  31.  
    }
  32.  
     
  33.  
    var copy = completeAssign ( { } , obj ) ;
  34.  
    console . log (copy ) ;
  35.  
    // { foo:1, get bar() { return 2 } }

Polyfill

polyfill不支持 symbol 属性,因为ES5 中根本没有 symbol :

  1.  
    if ( typeof Object .assign != 'function' ) {
  2.  
    // Must be writable: true, enumerable: false, configurable: true
  3.  
    Object . defineProperty ( Object , "assign" , {
  4.  
    value : function assign ( target , varArgs ) { // .length of function is 2
  5.  
    'use strict' ;
  6.  
    if (target == null ) { // TypeError if undefined or null
  7.  
    throw new TypeError ( 'Cannot convert undefined or null to object' ) ;
  8.  
    }
  9.  
     
  10.  
    var to = Object (target ) ;
  11.  
     
  12.  
    for ( var index = 1 ; index < arguments .length ; index ++ ) {
  13.  
    var nextSource = arguments [index ] ;
  14.  
     
  15.  
    if (nextSource != null ) { // Skip over if undefined or null
  16.  
    for ( var nextKey in nextSource ) {
  17.  
    // Avoid bugs when hasOwnProperty is shadowed
  18.  
    if ( Object .prototype .hasOwnProperty . call (nextSource , nextKey ) ) {
  19.  
    to [nextKey ] = nextSource [nextKey ] ;
  20.  
    }
  21.  
    }
  22.  
    }
  23.  
    }
  24.  
    return to ;
  25.  
    } ,
  26.  
    writable : true ,
  27.  
    configurable : true
  28.  
    } ) ;
  29.  
    }
个人分类:  前端开发 JavaScript

猜你喜欢

转载自www.cnblogs.com/wulihong/p/9295967.html