A directory

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

directory
A directory
The preface
Three shallow copy
 3.1 Handwritten shallow copy
 3.2 the Object. The assign
 3.3 an array of API
Four deep copy
 4.1 Handwritten deep Copy
 4.2 JSON. Parse (JSON. Stringify ())
 4.3 Function library Lodash
 4.4 Five Frameworks jQuery
V. References

The preface

Returns the directory

Interviewer: How do I shallow copy and deep copy an array?

To understand why we ask this question, we need to start with the address and value:

  • We copy references to the underlying data type, both copying the corresponding value
let number1 = 1;
let number2 = 2;

console.log(number1, number2); / / 1. 2

number2 = 3;

console.log(number1, number2); / / 1 3

// Copy the base data type and modify it without changing the original value (number1)
Copy the code
  • We copy references to complex data types by copying the corresponding addresses
let obj1 = {
  name: 'jsliang'};let obj2 = obj1;

console.log(obj1); // { name: 'jsliang' }
console.log(obj2); // { name: 'jsliang' }

obj2.name = 'zhazhaliang';

console.log(obj1); // { name: 'zhazhaliang' }
console.log(obj2); // { name: 'zhazhaliang' }

// Copy the reference data type and modify it to change the original value (obj1)
Copy the code

In simple terms, complex data types such as Array and Object create a space of their own to store data, and they reference corresponding addresses.

You can view the data in the Array as a family, so to find this family, do you need to have a household account, if you change a family member, do you change the household account information?

So, when you copy arrays or objects, you copy their addresses.

If you want to make changes without contaminating the original, you need to make deep copies.

Three shallow copy

Returns the directory

How to implement shallow copy? Generally, there are three situations:

  1. Handwritten shallow copy
  2. useObject.assign
  3. Use the array API, as inconcatorsliceAnd extend operators

3.1 Handwritten shallow copy

Returns the directory

const shallowClone = (target) = > {
  // Set the copy result
  const result = [];

  // Let... in ... traverse
  for (let prop in target) {

    // If the property is target's own
    // Instead of going through the prototype chain, assign the value
    if(target.hasOwnProperty(prop)) { result[prop] = target[prop]; }}// Return the copied result
  return result;
}
Copy the code
  • 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.

Of course, this can only copy arrays, but what about copying objects?

Let’s “slightly” refine it:

/ / by the Object. The prototype. ToString. Call (XXX) can determine a target attribute
// Object returns "[Object Object]"
// Array returns "[object Array]"
const checkedType = (target) = > {
  return Object.prototype.toString.call(target).slice(8, -1);
}

/ / shallow copy
const shallowClone = (target) = > {
  // Set the result
  let result;

  // If the target is an object, set it to an object
  if (checkedType(target) === 'Object') {
    result = {};
  } else if (checkedType(target) === 'Array') { // If the target is an array, set it to an array
    result = [];
  }

  / / by the let... in... Iterate over groups or objects
  // Use hasOwnProperty to determine whether it is its own property
  for (let i in target) {
    if(target.hasOwnProperty(i)) { result[i] = target[i]; }}// Returns the copy result
  return result;
};
Copy the code

Example test:

/* ———————————————— test array ———————————————— */
const arr1 = [1.2['jsliang'.'JavaScriptLiang'].4];
Array.prototype.sayHello = () = > console.log('hello');
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 ]

/* ———————————————— Test object ———————————————— */
const obj1 = {
  name: 'jsliang'.like: ['eat'.'play'],}Object.prototype.sayHello = () = > console.log('hello');
const obj2 = shallowClone(obj1);
console.log(obj2);
obj2.name = 'zhazhaliang';
obj2.like.push('sleep');

console.log(obj1); // { name: 'jsliang', like: [ 'eat', 'play', 'sleep' ] }
console.log(obj2); // { name: 'zhazhaliang', like: [ 'eat', 'play', 'sleep' ] }
Copy the code

3.2 the Object. The assign

Returns the directory

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! ']; // Modify the layer reference type

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

Object.assign Is used to copy objects.

It’s a full copy for the first layer; For layer 2 and above, it is simple copy.

3.3 an array of API

Returns the directory

  • Array.prototype.concat(target):concat()Is a built-in method of arrays where the user merges two or more arrays. Instead of changing an existing array, this method returns a new one.const b = [].concat(a)
  • Array.prototype.slice(start, end):slice()Is a built-in method of arrays that returns a new object.slice()It doesn’t change the original array.const b = a.slice()
  • Expansion operator:[...arr]You get a shallow-copy new array.

Four deep copy

Returns the directory

If an interviewer asks you about deep copy implementation, jsliang thinks the answer should go something like this:

  1. Handwritten deep copy
  2. With the help ofJSON.parse(JSON.stringify())
  3. Use third-party libraries like Lodash, jQuery, etc

Then, if the interviewer asks you how to do it by hand, use the code in the next section.

4.1 Handwritten deep Copy

Returns the directory

// 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 {
      // If not, assign the value directlyresult[i] = value; }}// Returns the final value
  return result;
}
Copy the code

Note that there are problems with this deep copy, such as:

  • Circular reference (passMaporSetRecord storage Space) (WeakMapIt works better here)
  • Reference at the same level
  • … Etc.

I’m not going to go into specific solutions here.

A simple test:

/* ———————————————— test array ———————————————— */
const arr1 = [1.2['jsliang'.'JavaScriptLiang'].4];
Array.prototype.sayHello = () = > console.log('hello');
const arr2 = deepClone(arr1);
arr2[2].push('LiangJunrong');
arr2[3] = 5;

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

/* ———————————————— Test object ———————————————— */
const obj1 = {
  name: 'jsliang'.like: ['eat'.'play'],}Object.prototype.sayHello = () = > console.log('hello');
const obj2 = deepClone(obj1);
obj2.name = 'zhazhaliang';
obj2.like.push('sleep');

console.log(obj1); // { name: 'jsliang', like: [ 'eat', 'play' ] }
console.log(obj2); // { name: 'zhazhaliang', like: [ 'eat', 'play', 'sleep' ] } 
Copy the code

4.2 JSON. Parse (JSON. Stringify ())

Returns the directory

  • JSON.stringify(): Converts the object toJSONA 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

4.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

4.4 Five Frameworks jQuery

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 () can be used as a deep copy in jQuery.

V. References

Returns the directory

  • How to write a deep copy that will impress your interviewer?[Reading Suggestions: 2H]
  • The ultimate quest for deep copy (90% of people don’t know)[Reading Suggestions: 1H]
  • JavaScript basics – deep and shallow copy[Recommended Reading: 30min]
  • Deep and shallow copy of JavaScript topics【 Reading Suggestions: 20min】
  • Implementation of shallow copy and deep copy in javaScript【 Reading Suggestions: 20min】
  • Deep dive into JavaScript deep copy【 Reading Suggestions: 20min】
  • “JavaScript” walks you through deep copy, shallow copy, and circular references【 Reading Suggestions: 20min】
  • How to implement a deep copy of the interview question[Recommended Reading: 30min]

Jsliang’s document library is licensed by Junrong Liang under the Creative Commons Attribution – Non-commercial – Share alike 4.0 International License. Based on the github.com/LiangJunron… On the creation of works. Outside of this license agreement authorized access can be from creativecommons.org/licenses/by… Obtained.