Shallow copy Object. The assign ()

Function: Copies the values of all enumerable properties from one or more source objects to the target object, and returns the target object.

Grammar:

Object.assign(target, ... sources)Copy the code

Where target is the target object, sources is the source object, there can be multiple, return the modified target object target.

If an attribute in the target object has the same key, the attribute value is overwritten by the attribute value in the source object.

Example 1:

/ / the first step
let a = {
    name: "dami".age: 3
}
let b = {
    name: "doudou".info: {
        title: "a cute cat".price: "6000"}}let c = Object.assign(a, b);
console.log(c);
/ / {
// name: "doudou",
// age: 3,
// info: {title: "a cute cat", price: "6000"}
// } 
console.log(c===a) // true

/ / the second step
b.name = 'change'
b.info.price = '10000'
console.log(b)
/ / {
// name: "change",
// age: 3,
// info: {title: "a cute cat", price: "10000"}
// } 

/ / the third step
console.log(a)
/ / {
// name: "doudou",
// age: 3
// info: {title: "a cute cat", price: "10000"}
// } 
Copy the code
  1. In the first step, we use object. assign to copy the value of source Object B to target Object A. The return value is defined as Object C. We can see that B will replace the value of A with the same key. Note that the return object C is the target object A.
  2. In the second step, modify the base and reference type values for source object B
  3. In step 3, the base type value of target Object A does not change after the shallow copy, but the reference type value changes because object.assign () copies attribute values. If the attribute of the source object is a reference to the object, it copies only that reference address.

Example 2: Properties of type Symbol are copied and source objects with values of NULL and undefined are not skipped.

let a = {
    name: "doudou".age: 3
}
let b = {
    b1: Symbol("doudou"),
    b2: null.b3: undefined
}
let c = Object.assign(a, b);
console.log(c);
/ / {
// name: "doudou",
// age: 3,
// b1: Symbol(doudou),
// b2: null,
// b3: undefined
// } 
console.log(a === c); // true
Copy the code

Object.assign() simulation implementation

The implementation idea is roughly as follows:

  1. Determine if the native Object supports this function. If it doesn’t, create a function assign and bind it to Object using Object.defineProperty
  2. Check whether the parameter is correct (the target object can not be null or undefined, can be {}, but must be set)
  3. Royalty Object() is converted to an Object, saved as to, and finally returned as to
  4. Use for… The in loop iterates through all enumerable own properties and copies them to the new target object (use hasOwnProperty to get own properties, i.e. properties that are not on the prototype chain)

The implementation code is as follows. Instead of assign, assign2 is used for easy verification. Note that this mock implementation does not support the Symbol attribute, as there is no symbol in ES5

if(typeof Object.assign2 ! = ='function') {
  // Note 1: An attribute mounted to an Object is not enumerable in its native form, but it is enumerable after it is mounted to an Object. DefineProperty must be used in enumerable: false and writable: True, configurable: true. Of course, the default is false.
  Object.defineProperty(Object.'assign2', {
    value: function(target) {
      'use strict'
      // Note 2: The target object cannot be undefined or null
      if(target == null) {
        throw new TypeEoor('Cannot convert null or undefined to object')}// Note 3: Object.assign() will be wrapped as an Object if the target Object is of primitive type. It is ok
      const to = Object(target)

      for(let i = 1; i< arguments.length; i++) {
        const nextSource = arguments[i]
        if(nextSource ! =null) { / / note 2
          // Note 4: The object. assign method definitely does not copy the attributes of the prototype chain, so we need to use hasOwnProperty(..) to simulate the implementation. Use myObject.hasownProperty (..) instead. This is problematic because some objects may not be attached to Object.prototype (e.g. created by object.create (null)), in which case myObject.hasownProperty (..) is used. The solution is as follows:
          for(const key in nextSource) {
            if(Object.prototype.hasOwnProperty.call(nextSource, key)) {
              to[key] = nextSource[key]
            }
          }
        }
      }
      return to
    },
    writable: true.configurable: true})}Copy the code

PS: Why use strict mode? Let’s start with an example:

const a = "abc";
const b = "def";
Object.assign(a, b); // TypeError: Cannot assign to read only property '0' of object '[object String]'
Copy the code

The reason is that the property descriptor of Object(” ABC “) is writable: false.

const myObject = Object( "abc" );

Object.getOwnPropertyNames( myObject );
// [ '0', '1', '2', 'length' ]

Object.getOwnPropertyDescriptor(myObject, "0");
/ / {
// value: 'a',
// writable: false, // notice here
// enumerable: true,
// configurable: false
// }
Copy the code

Similarly, the following code will also report an error.

const a = "abc";
const b = {
  0: "d"
};
Object.assign(a, b); 
// TypeError: Cannot assign to read only property '0' of object '[object String]'
Copy the code

This does not mean that writable: false will cause an error, as shown in the following code.

const myObject = Object('abc'); 

Object.getOwnPropertyDescriptor(myObject, '0');
/ / {
// value: 'a',
// writable: false, // notice here
// enumerable: true,
// configurable: false
// }

myObject[0] = 'd';
// 'd'

myObject[0];
// 'a'
Copy the code

Error not reported here, the reason is that JS silently failed to modify the non-writable attribute value, an error will be reported only in strict mode.

'use strict'
const myObject = Object('abc'); 

myObject[0] = 'd';
// TypeError: Cannot assign to read only property '0' of object '[object String]'
Copy the code

So we need to use strict mode when emulating object.assign ().

Reference: muyiy. Cn/blog / 4/4.2….