Opening Points:

  • This article will use recursive learning method to explore the knowledge points involved in “shallow copy and deep copy”, hope friends to copy these knowledge points in their mind, in the interview or work can be flexibly used.
const deepCloneKnowledgePoints = {
  title: 'Shallow and deep copy'.chapterOne: {
    title: 'Section one'.point: [
      'Shallow copy and deep copy initial exploration'.'Base data types and reference data types',]},chapterTwo: {
    title: 'Section 2'.point: [
      'Handwritten shallow copy'.'Object.assign()'.'Array.prototype.concat()'.'Array.prototype.slice()'.'... Obj expansion operator ',].extend: [
      'for... in'.'for... of'.'for... In and for... The difference between '.'hasOwnProperty',]},chapterThree: {
    title: 'Section 3'.point: [
      'Handwritten deep copy'.'JSON.parse(JSON.stringify())'.'Function library Lodash'.'the jQuery framework',].extend: [
      'typeof'.'instanceof'.'constructor',
      {
        point: 'Object.prototype.toString.call()'.extend: [
          'Function.prototype.apply()'.'Function.prototype.bind()'.'Function.prototype.call()'.'Difference between apply(), bind() and call()',]}, {point: 'JSON.parse(JSON.stringify())'.extend: [
          'JSON.parse()'.'JSON.stringify()',]}],},};Copy the code

A directory

What’s the difference between a free front end and a salted fish

directory
A directory
The preface
Three shallow copy and deep copy initial exploration
Four shallow copy
 4.1 Handwritten shallow copy
 4.2 the Object. The assign ()
 4.3 Array. The prototype. The concat ()
 4.4 Array. The prototype. The slice ()
 4.5… Obj expansion operator
Five deep copy
 5.1 Handwritten deep copy
 5.2 JSON. Parse (JSON. Stringify ())
 5.3 Function library Lodash
 JQuery 5.4 framework
Six summarize

The preface

Returns the directory

In the middle of writing business code, a scene suddenly occurred:

  • The backend partner needs me to send it both the source data returned by the interface and the new data after the page modification.

The code appears as follows:

// Initial data
const initData = {
  // ...
};

// finalData Data comes from initData
// However, changes to finalData cannot affect initData
const finalData = _.deepClone(initData);

// Return the final form result to the back end
// finalData and initData are two different copies of data
const result = {
  initData: initData,
  finalData: finalData,
};
return res;
Copy the code

If const finalData = initData, can we modify the data in finalData directly? Does it affect initData?

Let’s try it out:

const initData = { obj: '123' };
const finalData = initData;
finalData.obj = '456';
console.log(initData);
console.log(finalData);
// Guess what the two console. logs above return?
Copy the code

If not, what do we need to do to return the old and new comparison data to the back end?

Three shallow copy and deep copy initial exploration

Returns the directory

Now, let’s find out.

Before we do that, let’s look at the base and reference data types.

Data is divided into basic data types and reference data types.

  • Basic data types: String, Number, Boolean, Null, Undefined, Symbol. Basic data types are data stored directly on the stack.
  • Reference data type: Array, Object. A reference data type stores that the object is referenced on the stack, and the real data is stored in memory.

To visualize this, let’s look at the following code:

// Basic data type
let str1 = '123';
str2 = str1;
str2 = '456';
console.log(str1); / / '123'
console.log(str2); / / '456'

// Reference the data type
let arr1 = [1.2.3];
arr2 = arr1;
arr2.push(4);
console.log(arr1); // [1, 2, 3, 4]
console.log(arr2); // [1, 2, 3, 4]
Copy the code

As mentioned above, since the basic data type is stored directly, if we copy the basic data type and then modify the new data, the original data will not be affected.

When you copy a reference data type and modify the new data, it affects the original data.

Image examples:

  • I have a big farm with houses, cars, sheep and prairie.
  • Basic data type: I had one car before, and I bought another one so I have two cars, and the failure of one doesn’t affect the other. I had one house, and I built another, so I have two houses, and if one gets struck by lightning it doesn’t affect the other.
  • In front of my house is a prairie, where some rotten grass was eaten by sheep. The sheep died of disease because of eating rotten grass. The prairie is still the prairie, but there is less grass inside; Sheep are still sheep, but there are fewer sheep inside.

In JavaScript, individual properties like house and car are called basic data types, which have their own private domains that you can clone, but the new one doesn’t affect the old one.

And if it’s a collective property like sheep or prairie, it’s object data, and if we store it one by one, it’s too much trouble to find it all at once, so the browser gives it a big field and tells you how to find it. So when you modify the content in it (sheep eat grass, less grass), it changes internally.

OK, now that we know about basic and reference data types, let’s explore assignment, shallow copy, and deep copy:

/** * @name = */
const dataOne = {
  title: 'study'.number: ['jsliang'.'JavaScriptLiang'.'LiangJunrong']};const dataTwo = dataOne;
dataTwo.title = 'play';
dataTwo.number = ['null'];
console.log(dataOne);
// dataOne: { title: 'play', number: ['null'] }
console.log(dataTwo);
// dataTwo: { title: 'play', number: ['null'] }

/** * @name Shallow copy */
const dataThree = {
  title: 'study'.number: ['jsliang'.'JavaScriptLiang'.'LiangJunrong']};const dataFour = shallowClone(dataThree); // shallowClone to be implemented
dataFour.title = 'play';
dataFour.number = ['null'];
console.log(datadataThreeOne);
// dataThree: { title: 'study', number: ['null'] }
console.log(dataFour);
// dataFour: { title: 'play', number: ['null'] }

/** * @name Deep copy */
const dataFive = {
  title: 'study'.number: ['jsliang'.'JavaScriptLiang'.'LiangJunrong']};const dataSix = deepClone(dataFive); // deepClone to be implemented
dataSix.title = 'play';
dataSix.number = ['null'];
console.log(dataFive);
// dataFive: { title: 'study', number: ['jsliang', 'JavaScriptLiang', 'LiangJunrong'] }
console.log(dataSix);
// dataSix: { title: 'play', number: ['null'] }
Copy the code

As above, we draw the conclusion:

  • Assignment: A copy of a reference address. Modification of assigned data, whether of a base or reference data type, affects the original data.
  • Shallow copy: one layer copy. In a shallow copy, changing the basic data type does not affect the basic data type of the original data, while changing the reference data type affects the original data type.
  • Deep copy: Unlimited levels of copy. In deep copy, changing both the base data type and the reference data type does not affect the original data type.

A shallow copy is a copy of the first layer of data, whether array or string, etc., which is not affected by each other. 2. Others believe that shallow copy is valid only for primitive data types, and addresses are referenced for reference data types.

Jsliang distinguishes shallow copy from assignment. If you have a better opinion, please mention ~

Diagramming is shown below:

And whether the original data points to the same object The original data is the basic data type The raw data contains child objects
The assignment is Change causes the original data to change along with it Change causes the original data to change along with it
Shallow copy no Change [does not] change the original data with it Change causes the original data to change along with it
Deep copy no Change [does not] change the original data with it Change [does not] change the original data with it

Four shallow copy

Returns the directory

4.1 Handwritten shallow copy

Returns the directory

Before exploring shallow copy with tools, let’s try “hand-writing” a shallow copy:

const arr1 = [1.2['jsliang'.'JavaScriptLiang'].4];

const shallowClone = (arr) = > {
  const dst = [];
  for (let prop in arr) {
    if(arr.hasOwnProperty(prop)) { dst[prop] = arr[prop]; }}return dst;
}

const arr2 = shallowClone(arr1);
arr2[2].push('LiangJunrong');
arr2[3] = 5;

console.log(arr1);
// [ 1, 2, [ 'jsliang', 'JavaScriptLiang', 'LiangJunrong' ], 4 ]
console.log(arr2);
// [ 1, 2, [ 'jsliang', 'JavaScriptLiang', 'LiangJunrong' ], 5 ]
Copy the code

As you can see, when we change the reference data type inside the reference data type, the original data will still be affected, but when we change the basic data type inside the reference data type, the original data will not be affected.

So, before we go any further, let’s talk about what I did to better explain the code ideas above:

  1. To find thefor... in, found to belong toJavaScript statements and declarations“, so I created a directory for my document libraryStatements and declarations.
  2. foundfor... infor... ofSimilar, so they looked it up separatelyfor… infor… of“By the way, he compared the twofor… In and for… Comparison of.
  3. foundfor... ofYou can also talk about inheritance and prototype chains, so by the way, here are some of the articles I wrote in the interview:Inheritance and prototype chains.
  4. To find thehasOwnPropertyAnd found out I hadn’t built it yetObjectCategory, so a new directory:Object“And wrote ithasOwnProperty.

With that out of the way, let’s explain why the above code can shallow copy data:

  • for... in: traversalObjectobjectarr1To list the enumerable values.
  • hasOwnProperty(): Checks whether the enumerated value belongs to the objectarr1If it is inherited, remove it; if it is its own, copy it.

In this way, we have successfully realized the shallow copy, and understand the knowledge points involved ~

Here are three more convenient forms for fast shallow copy.

4.2 the Object. The assign ()

Returns the directory

The object.assign () method copies the enumerable properties of any number of source objects to the target Object and returns the target Object.

It is important to note, however, that Object.assgin() makes a shallow copy, copying references to the attributes of the Object, not the Object itself.

const obj1 = {
  username: 'LiangJunrong'.skill: {
    play: ['basketball'.'computer game'].read: 'book',},girlfriend: ['Spare tire # 1'.'Spare tire number 2'.'Spare tire number 3']};const obj2 = Object.assign({}, obj1);
obj2.username = 'jsliang'; // Modify the base type
obj2.skill.read = 'computer book'; // Change the basic layer 2 type
obj2.skill.play = ['footboll']; // Change the layer 2 reference type
obj2.girlfriend = ['It was all bullshit! '];
console.log(obj1);
// { username: 'LiangJunrong',
// skill: { play: [ 'footboll' ], read: 'computer book' },
Girlfriend: [' no. 1 ', 'No. 2 ',' No. 3 ']}
console.log(obj2);
// { username: 'jsliang',
// skill: { play: [ 'footboll' ], read: 'computer book' },
// Girlfriend: [' Girlfriend was full of shit! ']}
Copy the code

As you can see, object.assign () is a deep copy for layer 1 data and a shallow copy for layer 2 and above data.

4.3 Array. The prototype. The concat ()

Returns the directory

Concat () is a built-in method for arrays that allows the user to merge two or more arrays.

Instead of changing an existing array, this method returns a new one.

For more information, see Jsliang’s article or MDN’s article:

  • jsliang – Array.prototype.concat()
  • MDN – Array.prototype.concat()

Here, we shallow copy an array by concat() :

const arr1 = [
  1,
  {
    username: 'jsliang',},];let arr2 = arr1.concat();
arr2[0] = 2;
arr2[1].username = 'LiangJunrong';
console.log(arr1);
// [ 1, { username: 'LiangJunrong' } ]
console.log(arr2);
// [ 2, { username: 'LiangJunrong' } ]
Copy the code

A shallow copy of concat() can change the base datatype without affecting the original value, but changes to the reference datatype will affect the original value.

4.4 Array. The prototype. The slice ()

Returns the directory

Slice () is also a built-in method of arrays that returns a new object.

Slice () does not alter the array.

For details, please refer to CONCat of Jsliang or MDN literature directly:

  • jsliang – Array.prototype.concat()
  • MDN – Array.prototype.concat()
const arr1 = [
  1,
  {
    username: 'jsliang',},];let arr2 = arr1.slice();
arr2[0] = 2;
arr2[1].username = 'LiangJunrong';
console.log(arr1);
// [ 1, { username: 'LiangJunrong' } ]
console.log(arr2);
// [ 2, { username: 'LiangJunrong' } ]
Copy the code

Concat () and array.prototype.slice () are the source code implementations for array.prototype.concat () and array.prototype.slice ().

4.5… Obj expansion operator

Returns the directory

The expansion operator is a new addition to ES6.

It can be used for copying arrays, objects, and concatenating arrays.

Here we can also try using const obj2 = {… Make a shallow copy of obj1}.

/** * @name ... Obj copy array */
const arr1 = [1.2.3];
const arr2 = [...arr1]; // like arr.slice()
arr2.push(4); 

console.log(arr1); // [1, 2, 3]
console.log(arr2); // [1, 2, 3, 4]

/** * @name ... Obj Copy object */
const obj1 = {
  name: 'jsliang'.arr1: ['1'.'2'.'3'].obj: {
    name: 'JavaScriptLiang'.arr2: ['4'.'5'.'6'],}};constobj2 = {... obj1}; obj2.name ='LiangJunrong';
obj2.arr1 = ['null'];
obj2.obj.name = 'jsliang';
obj2.obj.arr2 = ['null'];

console.log(obj1);
// { name: 'jsliang',
// arr1: [ '1', '2', '3' ],
// obj: { name: 'jsliang', arr2: [ 'null' ] } }
console.log(obj2);
// { name: 'LiangJunrong',
// arr1: [ 'null' ],
// obj: { name: 'jsliang', arr2: [ 'null' ] } }
Copy the code

Five deep copy

Returns the directory

5.1 Handwritten deep copy

Returns the directory

Section 1 – – –

So, handwritten deep copy, how to achieve?

Let’s try modifying the previous shallow-copy code slightly:

const deepClone = (source) = > {
  const target = {};
  for (const i in source) {
    if (source.hasOwnProperty(i)
      && target[i] === 'object') {
      target[i] = deepClone(source[i]); // Notice here
    } else{ target[i] = source[i]; }}return target;
};
Copy the code

Of course, there are problems with this code:

  1. The parameters are not checked. If they are not an object or an array, we simply return them.
  2. throughtypeofDetermine if the object’s logic is not rigorous enough.

— — — — – section 2

Since there are problems, we need to try to overcome them:

// Define a function that detects data types
const checkedType = (target) = > {
  return Object.prototype.toString.call(target).slice(8.- 1);
}

// Implement deep clone object or array
const deepClone = (target) = > {
  // Determine the type of data to copy
  // Initialize the variable result to be the final data
  let result, targetType = checkedType(target);
  if (targetType === 'Object') {
    result = {};
  } else if (targetType === 'Array') {
    result = [];
  } else {
    return target;
  }

  // Iterate over the target data
  for (let i in target) {
    // Get the value of each item traversing the data structure
    let value = target[i];
    // Check whether each item in the target structure has an object or array
    if (checkedType(value) === 'Object' || checkedType(value) === 'Array') {
      // If there are nested objects or arrays in the object or array, continue iterating
      result[i] = deepClone(value);
    } else{ result[i] = value; }}// Returns the final value
  return result;
}

const obj1 = [
  1.'Hello! ',
  { name: 'jsliang1'[{},name: 'LiangJunrong1',}]]const obj2 = deepClone(obj1);
obj2[0] = 2;
obj2[1] = 'Hi! ';
obj2[2].name = 'jsliang2';
obj2[3] [0].name = 'LiangJunrong2';

console.log(obj1);
/ / /
/ / 1.
// 'Hello! ',
// { name: 'jsliang1' },
/ / /
// { name: 'LiangJunrong1' },
/ /,
// ]

console.log(obj2);
/ / /
/ / 2,
// 'Hi! ',
// { name: 'jsliang2' },
/ / /
// { name: 'LiangJunrong2' },
/ /,
// ]
Copy the code

Here’s a look at the deep-copy code:

First of all, we see check the type of the first line of code: Object. The prototype. ToString. Call (target). Slice (8, 1).

Before we get to that line of code, let’s compare the four ways we can detect JavaScript data types:

  • Method 1: Typeof: Impossible to judgenullornew String()And other data types.
  • Method 2: Instanceof: Impossible to judge'jsliang',123And other data types.
  • B) ConstructorJudge:nullundefinedAn error is reported directly.
  • Method 4: Object. The prototype. ToString. Call () : It can judge the basic data types such as String and Undefined as well as reference data types such as Array and Object.

For detailed study, please refer to jsliang’s learning document:

  • “Determining Data Types – Summary”
  • Determining data Types – Typeof
  • Determining Data Types – Instanceof
  • Judging Data Types – Constructor
  • “Determining data Types – toString”

Then, we through the method of targetType () in the Object. The prototype. ToString. Call (), to judge the incoming data type belongs to the kind, Change the value of result to {}, [], or simply return the value passed in (return target).

Finally, we pass for… In determines all elements of target. If they belong to {} or [], clone() is performed recursively. If it is a primitive data type, it is passed directly into an array… A deep copy of the data is returned at the end.


Section 3 – – –

Above, our code seems to be ok, isn’t it? Suppose we need to copy the following data:

const obj1 = {};
obj1.a = obj1;
console.log(deepClone(obj1));
// RangeError: Maximum call stack size exceeded
Copy the code

Look, we just created an infinite loop!

So what do we need to do about it? To be realized!

Before I come up with a solution, you can read the following article and think about whether you can solve the problem:

  • What are deep and shallow JS copies and how to implement them
  • Shallow and deep copies of JavaScript
  • Interview question how to implement a deep copy – wood yi Yang

… OK, although I hope you can read the information by yourself, but in order to prevent the blade sent, Jsliang still write down the code that I think is OK here:

function isObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

function deepClone(source, hash = new WeakMap()) {
  if(! isObject(source))return source;
  // add code to check hash table
  if (hash.has(source)) return hash.get(source);

  var target = Array.isArray(source) ? [] : {};
  // Add code, hash table set value
  hash.set(source, target);

  for (var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      if (isObject(source[key])) {
        // Add code to pass in hash table
        target[key] = deepClone(source[key], hash);
      } else{ target[key] = source[key]; }}}return target;
}

/** * @name Normal deep copy test */
const a = {
  name: 'jsliang'.book: {
    title: 'Deep copy learning'.price: 'free',},a1: undefined.a2: null.a3: 123
};
const b = deepClone(a);
b.name = 'JavaScriptLiang';
b.book.title = 'Teach you how to pick up women.';
b.a3 = 456;
console.log(a);
// { name: 'jsliang',
// book: {title: 'deep copy learning ', price: 'free'},
// a1: undefined,
// a2: null,
// a3: 123 }
console.log(b);
// { name: 'JavaScriptLiang',
// book: {title: 'how to get girls ', price: 'free'},
// a1: undefined,
// a2: null,
// a3: 456 }

/** * @name resolves an infinite loop */
const c = {};
c.test = c;
const d = deepClone(c);
console.log(c);
// { test: [Circular] }
console.log(d);
// { test: [Circular] }
Copy the code

— — — — – section 4

Now that we’re done with the dead loop, let’s look at another problem:

const checkedType = (target) = > {
  return Object.prototype.toString.call(target).slice(8.- 1);
}

const deepClone = (target) = > {
  let result, targetType = checkedType(target);
  if (targetType === 'Object') {
    result = {};
  } else if (targetType === 'Array') {
    result = [];
  } else {
    return target;
  }

  for (let i in target) {
    let value = target[i];
    if (checkedType(value) === 'Object' || checkedType(value) === 'Array') {
      result[i] = deepClone(value);
    } else{ result[i] = value; }}return result;
}

// Detect depth and breadth
const createData = (deep, breadth) = > {
  const data = {};
  let temp = data;

  for (let i = 0; i < deep; i++) {
    temp = temp['data'] = {};
    for (let j = 0; j < breadth; j++) { temp[j] = j; }}return data;
};

console.log(createData(1.3)); 
/ / 1 layer depth, each layer has three data {data: {' 0 ': 0,' 1 ', 1, '2', 2}}

console.log(createData(3.0));
Data: {data: {data: {data: {}}}}

console.log(deepClone(createData(1000)));
{data: {data: {data: [Object]}}}

console.log(deepClone(createData(10.100000)));
// 100000 breadth, no problem, data traversal takes time

console.log(deepClone(createData(10000)));
// 10000 layers: Maximum Call stack size exceeded
Copy the code

Yes, your deep copy is out of stack!!

Although the probability of stack burst is relatively small in business scenarios, after all, there are not so many data layers, but this situation still exists, how to deal with it?

Those who just want to get a general idea of what deep copy can do can skip the following

For example, suppose there is a data structure:

const a = {
  a1: 1.a2: {
    b1: 1.b2: {
      c1: 1}}};Copy the code

If we think of it as a number:

    a
  /   \
 a1   a2        
 |    / \         
 1   b1 b2     
     |   |        
     1  c1
         |
         1
Copy the code

Then we can iterate through the tree!

  1. First, we need to use the stack. When the stack is empty, the traversal is completed, and the stack stores the next node that needs to be copied
  2. Then, we put seed data on the stack,keyCopy object of the child element used to store which parent element
  3. Finally, it iterates through the children of the current node, putting them on the stack if they are objects, and copying them otherwise.
const deepClone = (x) = > {
  const root = {};

  / / stack
  const loopList = [
    {
      parent: root,
      key: undefined.data: x
    }
  ];

  while (loopList.length) {
    // Depth first
    const node = loopList.pop();
    const parent = node.parent;
    const key = node.key;
    const data = node.data;

    // Initialize the assignment target. If key is undefined, copy it to the parent element, otherwise copy it to the child element
    let res = parent;
    if (typeofkey ! = ="undefined") {
      res = parent[key] = {};
    }

    for (let k in data) {
      if (data.hasOwnProperty(k)) {
        if (typeof data[k] === "object") {
          // Next loop
          loopList.push({
            parent: res,
            key: k,
            data: data[k]
          });
        } else{ res[k] = data[k]; }}}}return root;
}
Copy the code

CreateData width and depth check; createData width and depth check

console.log(deepClone(createData(10.100000)));
// 100000 breadth, no problem, data traversal takes time

console.log(deepClone(createData(100000)));
{data: {data: {data: [Object]}}}
Copy the code

In this way, we solve the problem of stack bursting.

It is recommended to refer to the article “The Ultimate Quest for deep copy”, and then it comes with a deep copy library: @jsmini/ Clone, interested friends can check it out.

5.2 JSON. Parse (JSON. Stringify ())

Returns the directory

Parse (json.stringify ())

  • JSON.stringify(): Converts the object to a JSON string.
  • JSON.parse(): Parses strings into objects.

Parse (json.stringify ()) serializes JavaScript objects (converting them to JSON strings) and returns them to JavaScript objects. As soon as we do that, we create a new object and the object opens up a new stack. To achieve deep copy.

Note that this method has the following limitations: 1. It cannot store function or Undefined, otherwise it will lose function or Undefined. 2, do not store the time object, otherwise it will become a string; 3. Do not store RegExp or Error objects, otherwise they will become empty objects. 4, can not store NaN, Infinity, -infinity, otherwise will be null; 5,… To be specific, there are differences between JavaScript and JSON, and the two incompatible will cause problems.

const arr1 = [
  1,
  {
    username: 'jsliang',},];let arr2 = JSON.parse(JSON.stringify(arr1));
arr2[0] = 2;
arr2[1].username = 'LiangJunrong';
console.log(arr1);
// [ 1, { username: 'jsliang' } ]
console.log(arr2);
// [ 2, { username: 'LiangJunrong' } ]
Copy the code

5.3 Function library Lodash

Returns the directory

Lodash is a popular JavaScript function library/tool library, it has very good encapsulation function, you can try:

  • Lodash

Here we look at its cloneDeep() method:

  • Lodash – _.cloneDeep(value)

As you can see, this method copies the value recursively.

Here we experience its cloneDeep() :

// npm i -S lodash
var _ = require('lodash');

const obj1 = [
  1.'Hello! ',
  { name: 'jsliang1'[{},name: 'LiangJunrong1',}]]const obj2 = _.cloneDeep(obj1);
obj2[0] = 2;
obj2[1] = 'Hi! ';
obj2[2].name = 'jsliang2';
obj2[3] [0].name = 'LiangJunrong2';

console.log(obj1);
/ / /
/ / 1.
// 'Hello! ',
// { name: 'jsliang1' },
/ / /
// { name: 'LiangJunrong1' },
/ /,
// ]

console.log(obj2);
/ / /
/ / 2,
// 'Hi! ',
// { name: 'jsliang2' },
/ / /
// { name: 'LiangJunrong2' },
/ /,
// ]
Copy the code

We use Node to install its dependency package. If you need to use MDN, you can visit its official website. (Address at the beginning of this section)

JQuery 5.4 framework

Returns the directory

Of course, if your company still uses jQuery, you may need to be ie6/7/8 compliant, or you use React, but there are some scenarios that use jQuery. JQuery is a powerful framework.

Extend () :

index.html

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Document</title> </head> <body> <p JQuery deep copy < / p > < script SRC = "https://cdn.bootcss.com/jquery/3.4.1/jquery.js" > < / script > < script > $(function () {const obj1  = [ 1, 'Hello!', { name: 'jsliang1' }, [ { name: 'LiangJunrong1', } ], ] const obj2 = {}; /** * @description $. Extend (deep, target, object1, object2...) * @param {Boolean} deep The value can be true or false. The default value is false. $.extend(true, obj2, obj1); $.extend(true, obj1); obj2[0] = 2; obj2[1] = 'Hi! '; obj2[2].name = 'jsliang2'; obj2[3][0].name = 'LiangJunrong2'; console.log(obj1); // [ // 1, // 'Hello!', // { name: 'jsliang1' }, // [ // { name: 'LiangJunrong1'}, // ], // ]; console.log(obj2); // [ // 2, // 'Hi!', // { name: 'jsliang2' }, // [ // { name: 'LiangJunrong2' }, // ], // ]; }); </script> </body> </html>Copy the code

Here, we tried a deep copy of the jQuery CDN package by referencing it in index.html, since Node didn’t try to reference the package directly.

It is recommended that you use the live-server to monitor HTML file changes in real time

Deep copy and shallow copy implementation (a) “JavaScript shallow copy and deep copy”

JQuery. Extend the source code

jQuery.extend = jQuery.fn.extend = function() {
  var options,
    name,
    src,
    copy,
    copyIsArray,
    clone,
    target = arguments[0] || {},
    i = 1,
    length = arguments.length,
    deep = false;

  // Handle a deep copy situation
  if (typeof target === "boolean") {
    deep = target;

    // Skip the boolean and the target
    target = arguments[i] || {};
    i++;
  }

  // Handle case when target is a string or something (possible in deep copy)
  if (typeoftarget ! = ="object" && !jQuery.isFunction(target)) {
    target = {};
  }

  // Extend jQuery itself if only one argument is passed
  if (i === length) {
    target = this;
    i--;
  }

  for (; i < length; i++) {
    // Only deal with non-null/undefined values
    if ((options = arguments[i]) ! =null) {
      // Extend the base object
      for (name in options) {
        src = target[name];
        copy = options[name];

        // Prevent never-ending loop
        if (target === copy) {
          continue;
        }

        // Recurse if we're merging plain objects or arrays
        if (
          deep &&
          copy &&
          (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))
        ) {
          if (copyIsArray) {
            copyIsArray = false;
            clone = src && Array.isArray(src) ? src : [];
          } else {
            clone = src && jQuery.isPlainObject(src) ? src : {};
          }

          // Never move original objects, clone them
          target[name] = jQuery.extend(deep, clone, copy);

          // Don't bring in undefined values
        } else if(copy ! = =undefined) { target[name] = copy; }}}}// Return the modified object
  return target;
};
Copy the code

Six summarize

Returns the directory

Unfortunately, we have temporarily completed the first phase of shallow copy and deep copy exploration

In writing this series, jsliang hesitated, stayed up late, thought about giving up… But I persevered and went through it.

In the process of searching materials to enrich the series of knowledge, Jsliang neglected some knowledge points to explore, otherwise there will be more confusion, and finally every day until 04:00 PM is still in high spirits

Some of the points we haven’t explored are:

  1. How does Lodash implement deep copy
  2. How does jQuery implement deep copy
  3. Object. Assign principle and its implementation

Some of you might think:

  • Oh, don’t you feel ashamed to publish it before you have made a thorough investigation?

enm… How to say, first of all, when writing this article, Jsliang is to explore the breadth, that is, to contact and understand every knowledge point encountered, in fact, this writing is very tired, but the progress is very big, because you dig out some knowledge points.

However, jsliang’s initial goal was just to understand the deep copy of handwriting, and some tools to quickly achieve deep copy, so I think this goal has been reached or even exceeded.

Finally, there are also some knowledge points, such as writing an object.assign () or understanding Lodash’s deep copy source code. If you want to know more about it, you will definitely explore it by yourself.

After all: don’t toss the front end, what’s the difference with salted fish!

Therefore, if you want to continue to follow up, you can go to jsliang’s GitHub warehouse home page to find my official account, wechat, QQ and other contact information.

So, I’ll see you later

  • References:
  1. Lodash clone series
  2. Shallow copy and deep copy
  3. The ultimate quest for deep copy
  4. Implementation of Deep copy and Shallow Copy (1)
  5. Deep copy and shallow copy
  6. What are deep and shallow JS copies and how to implement them
  7. Shallow and deep copies of JavaScript
  8. Js deep copy vs shallow copy
  9. The ultimate quest for deep copy (unknown to 99% of people)
  10. How to implement a deep copy of the interview question

Jsliang advertising push: maybe partners want to know about the cloud server or partners want to buy a cloud server or partners need to renew the cloud server welcome to click on the cloud server promotion view!



Jsliang document library 由 Liang JunrongusingCreative Commons Attribution – Non-commercial Use – Same way Share 4.0 International LicenseGrant permission.

Based on theGithub.com/LiangJunron…On the creation of works.

Use rights other than those authorized by this License agreement may be obtained fromCreativecommons.org/licenses/by…Obtained.