JavaScript replication objects cannot achieve deep copying with object.assign methods

In this language of JavaScript, data types are divided into two categories: basic data types and complex data types. Basic data types include Number, Boolean, String, Null, String, Symbol (new), and complex data types include Object, and all other reference types (Array, Date, Regexp, Function, Basic Packaging Types (Boolean, String, Number, Math, etc.) are an instance object of an Object type, so some properties and methods of the Object prototype object can be inherited.

For the basic data type, copy a variable value is essentially COPY this variable. A modification of a variable does not affect another variable. Look at a simple example.


Let Val = 123; Let Copy = Val; Console.log (Copy); // 123Val = 456; // Modify VAL’s value to COPY The value does not affect Console.log (copy); // 123
   For complex data types, it is not too the same as the basic data type. For a replication of complex data types, it is to be noted that the variable name just points to the pointer to this object. When we assign a variable of saving the object to another variable, the pointer is actually copied, and both variables point to all objects. Therefore, an object of an object will affect another object. 
// OBJ just points to the pointer Let Obj = {Character: ‘peaceful’}; // COPY variable, pointing to the same object Let Copy = Obj; Console.log (copy); // {Character: ‘peaceful’}Obj.Character = ‘love’; console.log (copy); // {character: ‘lovely’}


There is a very image of diagram to describe complex data types Principle
   
When copying an array, the variable name just points to the pointer to this array object; when copying a function, the function name just points to this function object. Pointer

Let Arr = [1, 2, 3]; Let Copy = Arr; Console.log (Copy); // [1, 2, 3] Arr [0] = ‘keith’; console.log (copy); // array object is changed: [‘keith’, 2, 3] Arr = null; console.log (copy); // [‘keith ‘, 2, 3] Even if Arr = NULL, it will not affect COPY. So, the Arr variable at this time is just a pointer function foo () {return ‘Hello World’;}; let bar = foo; console.log (foo ()); foo = null; // foo just point to functions The object’s pointer console.log (bar ());

JavaScript 复制对象与Object.assign方法无法实现深复制 Therefore, how should we achieve the dark copy of the object?


Copy the object

In JavaScript, the replication object is divided into two ways, shallow copy and deep recharging.
  Shallow copy There is no way to realize an object, but only saves a reference to this object; and deep reductive can realize an object.  
Shallow Repair

In ES6, the Object object adds an ASSIGN method to realize shallow copy of the object. Here, talk about the specific usage of the object.assign method, because later analyze the EXTEND method of jQuery, the principle of implementation is similar to the object.assign method

Object.assign’s first parameter is the target object, you can follow One or more source objects are copied to the target object as a parameter, copy all the enumerated enumerations of the source object to the target object. This copy belongs to shallow relics and replicates the object only to the reference to the object. Object.assign (Target, [Source1, Source2, …])

If the target object has the same name attribute, the later property covers the previous attribute

If there is only one parameter, the parameter is returned directly. That is, Object.assign (OBJ) === Obj

If the first parameter is not an object, but the basic data type (except NULL, undefined), the corresponding basic package type

If the first parameter is null and undefined, it will be reported; if null and undefined are not in the first parameter, the copy of the parameter will be slightly replicated

To realize the shallow copy of the object, Object.assign method

  • let target = {A: 123}; let source1 = {B: 456}; let source2 = {C: 789} Let Obj = Object.assign (target, source1, source2); console.log (obj);
  • However, for deep recurrence, OBJThe ECT.Assign method cannot achieve

Let target = {a: 123}; let source1 = {B: 456}; let source2 = {C: 789, D: {E: ‘Lovely’}}; let Obj = Object.assign (target, source1, source2); source2.de = ‘peaceful’; console.log (obj); // {a: 123, b: 456 , C: 789, D: {E: ‘peaceful’}}

From the above code, it can be seen that the changes in the E attribute in the Source2 object will still affect OBJ Object
Deep Replication
   In the actual development project, data transmission is performed by the front and rear ends, mainly through JSON implementation. JSON full name: JavaScript Object Notation, JavaScript object representation. 
There are two methods under the JSON object. One is to convert JS objects into a string object’s JSON.Stringify method; one is a JSON.PARSE method for converting string objects into JS objects.

These two methods combine to use the deep remedies of the object. That is, when we need to copy an OBJ object, you can call JSON.STRINGY (OBJ), convert it into a string object, then call the JSON.PARSE method to convert it to the JS object. Easily realize the deep transcription of the object

 Let Obj = {A: 123, B: {C: 456, D: {E: 789}} };Copy = json.parse (json.stringify (obj)); // does not affect the OBJ object, no matter how modified, Copy object obj.bc = 'hello'; obj.bde = 'world'; console.log COPY); // {a: 123, b: {C: 456, D: {E: 789}}}   
Of course, use this way to achieve deep replication One disadvantage is that the string must be incorporated into the JSON.PARSE method must be a legal JSON, otherwise the error will be thrown

jQuery.extend || jQuery.fn.extend

jQuery.extend object, does not default for friends who use jQuery more than a certain time. This $ .extend method can be used to extend the global object of jQuery, and $ .fn.extend method can be used to extend instance objects. FN is actually an alias of the Prototype object, so the method of extending instance objects is actually adding some methods on the jQuery prototype object. $. The extend method can not only be used to write jQuery plugins, but it can be used to achieve the dark copy of the object. (Use $ .extend with $ .fn.extend to implement dark copy, the only difference is the point of directivity of this)

Before the specific analysis source code, I saw $ .Extend in the source code. Method’s characteristics

When no parameters are accepted, it is directly returned to an empty object


When there is only one parameter (this parameter can be any data type (null, undefined, boolean, String, Number, Object)), will return the THIS object, which is divided into two cases. If you use $ .extend, you will return jQuery objects; if you use $ .fn.extenD, will return jQuery’s prototype object.

When two parameters are received, an empty object is returned when the first parameter is a boolean value. If the first parameter is not a Boolean value, then the source object is copied to the target object
 When receiving three parameters, it can be divided into two cases. If the first parameter is the Boolean value indicates the depth of the depth, the target object will move to the second parameter, and the source object will move to the third parameter. (The target object, the source object, and the same object.Assign method). If the first parameter is not a boolean value, the usage is the same as the Object.Assign method.   In the process of cyclic source objects, any data type is null, undefined, or source object is an empty object, it is ignored during replication. 
If the source object and the target object have the same name, the properties of the source object overwrite the properties in the target object. If the same name attribute is an object, it will add attributes to the same name object of the target object under other conditions such as Deep = True

JQuery-2.1.4 in jQuery.Extend implementation method. Source code

jQuery.extend = jQuery.fn.extend = function () {var Options, Name, SRC, COPY, COPYISAARRAY, Clone, Target = Arguments [0] || {}, // Use the || operator, exclude implicit mandatory types to convert to false data type //, such as’, 0, undefined, null, false, etc. // If target is the value above Settable Target = {} i = 1, Length = arguments.lENGTH, Deep = false; // When typeof target === ‘boolean’ is set to target value // then move Target to the second parameter, if (typeof target === “boolean” ) {Deep = target; // Use the || operator, exclude implicit mandatory types to convert to false data type //, such as’, 0, undefined, null, false, etc. // If the target is the value above, set Target = {} Target = arguments [i] || {}; i ++;} // If the target is not an object or group or function, set Target = {} / / here is different from Object.Assign’s processing method, // Assign method converts Boolean, String, Number method to the corresponding basic packaging type / / then return, // and the extend method directly converts TypeOf not the data type // of the Object or Function to an empty object IF (TYPEOF TARGET! == “Object” &&! jQuery.isfunction (target)) {target = {};} // If arguments.length === 1 or // typeof arguments [0] === ‘boolean’, And there is Arguments [1], // This time the target object will point to this // this point to which object needs to be used to use $ .fn.extend or $ .extend if (i === length) {target =THIS; // I – means not entering the for loop i -;} // cycle arguments class number object, starting for For (; i

)

Therefore, Some examples


Let Obj1 = $ .Extend (); console.log (obj1); // Return an empty Object {} let Obj2 = $ .Extend (undefined); Console.log (obj2); // Returns the jQuery object, Object.assign is incorporated to report error LET OBJ3 = $ .Extend (‘123’); console.log Obj3); // Return to jQuery objects, Object.assign incomplete the ‘123’ will return the string String object Let target = {a: 123, b: 234}; let source1 = {B: 456, D: [kTh ‘,’ peaceful ‘,’ love ‘]}; let source2 = {c: 789}; let source3 = {}; let Obj4 = $ .Extend (target, source1, source2); // let Obj4 = $ .Extend ( False, Target, Source1, Source2; Console.log (Obj4); // {A: 123, B: 456, D: Array (3), C: 789} // By default, copy mode is shallow copy // If you only need shallow copying, it is not possible to copy the DEEP parameter or //, the D attribute in the OBJ4 object is only pointing to the array object.Needle let obj5 = $ .extend (target, undefined, source2); let obj6 = $ .extend (target, source3, source2); console.log (obj5, obj6); // {a: 123, b: 234, c : 789}, {A: 123, B: 234, C: 789} // will slightly Object or undefined, NULL value let Obj7 = $ .Extend (True, Target, Source1, Source2); Console.log (Obj7 ); // {a: 123, b: 456, d: Array (3), c: 789} // b where the target object has attributes, the source object has source1 b b // At this attribute of the source object property overrides @ b where properties of the target object deep = true, when part of a deep-copy @ name = d, recursively calls $ .extend, until it’s corresponding attribute values ​​of all attributes of the source object changes substantially // data type It will affect the OBJ7 object

JavaScript copy object
  < length; i++) {
    // 针对下面if判断
    // 有一点需要注意的是
    // 这里有一个隐式强制类型转换 undefined == null 为 true
    // 而undefined === null 为 false
    // 所以如果源对象中数据类型为Undefined或Null
    // 那么就会跳过本次循环,接着循环下一个源对象
    if ((options = arguments[i]) != null) {
      // 遍历所有[[emuerable]] === true的源对象
      // 包括Object, Array, String
      // 如果遇到源对象的数据类型为Boolean, Number
      // for in循环会被跳过,不执行for in循环
      for (name in options) {
        // src用于判断target对象是否存在name属性
        src = target[name];

        // 需要复制的属性
        // 当前源对象的name属性
        copy = options[name];

        // 这种情况暂时未遇到..
        // 按照我的理解,
        // 即使copy是同target是一样的对象
        // 两个对象也不可能相等的..
        if (target === copy) {
          continue;
        }

        // if判断主要用途:
        // 如果是深复制且copy是一个对象或数组
        // 则需要递归jQuery.extend(),
        // 直到copy成为一个基本数据类型为止
        if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
          // 深复制
          if (copyIsArray) {
            // 如果是copy是一个数组
            // 将copyIsArray重置为默认值
            copyIsArray = false;
            // 如果目标对象存在name属性且是一个数组
            // 则使用目标对象的name属性,否则重新创建一个数组,用于复制
            clone = src && jQuery.isArray(src) ? src : [];

          } else {
            // 如果目标对象存在name属性且是一个对象
            // 则使用目标对象的name属性,否则重新创建一个对象,用于复制
            clone = src && jQuery.isPlainObject(src) ? src : {};
          }

          // 因为深复制,所以递归调用jQuery.extend方法
          // 返回值为target对象,即clone对象
          // copy是一个源对象
          target[name] = jQuery.extend(deep, clone, copy);

        } else if (copy !== undefined) {
          // 浅复制
          // 如果copy不是一个对象或数组
          // 那么执行elseif分支
          // 在elseif判断中如果copy是一个对象或数组,
          // 但是都为空的话,排除这种情况
          // 因为获取空对象的属性会返回undefined
          target[name] = copy;
        }
      }
    }
  }

  // 当源对象全部循环完毕之后,返回目标对象
  return target;
};   

 According to the $ .Extend method, a universal implementation can be written Object shallow replication function, the only difference between the CopyObject function is when I === arguments.length, the copyObject function returns Target object directly 


Function CopyObject () {let i = 1, target = arguments [0] || {}, deep = false, length = arguments.length, nAME, OPTIONS, SRC, COPY, COPYISAARRAY, Clone; // If the data type of the first parameter is boolean type // target next to the second parameter IF (TypeOf target === ‘Boolean’) {Deep = Target ; // Use the || operator to exclude the implicit mandatory type to convert to false data type //, such as’, 0, undefined, null, false, etc. //, set target = {} Target = arguments [1] || {}; i ++;} // If Target is not an object or array or function IF (TypeOf Target! == ‘Object’ &&! (Target === Function ‘) {target = {};} // If arguments.length === 1 or // typeof arguments [0] === ‘boolean’, // and there is arguments [1], then return Target object IF (i === Length ) {return target;} // Cycle Each source object for (; i
   The above is all the content of this article, I hope to help everyone, I hope Everyone supports Tumi Cloud. 
© Copyright Notice
THE END
Just support it if you like
like0
share
comment Grab the couch

Please log in to comment