Interviewer: Please tell me about deep and shallow copying and handwriting deep and shallow copying. Me: How do you know that I only know this?

Front-end and back-end interview question banks (necessary for interviews) Recommended: ★★★★★

Address: front-end interview question bank   web front-end interview question bank VS java back-end interview question bank Daquan

I. Introduction

When we need to deal with objects and arrays in JavaScript, we often need to use the copy function of objects and arrays. There are two copy methods in JS: deep copy and shallow copy. The duplication effects of the two methods are different, and the applicable scenarios are also different.

2. What are shallow copy and deep copy?

1. Shallow copy

Shallow copy is to copy the first layer of the object or array. If the attribute is basic type data, it will be copied directly. If it is reference type data, it will only shallow copy a reference (memory address). This reference points to the original Reference type data. This means that if the copied data is modified, the original reference type data will also be changed 会受到影响.

2. Deep copy

In JavaScript, deep copy refers to completely copying an object or array to generate a new one, no matter how many layers of nesting relationships there are, it must be completely independent. In other words, deep copy implements a real copy rather than a reference. If the copied object or array is modified, the original object or array is also modified 不会受到影响.

3. The difference between shallow copy and deep copy

The new object and the original object obtained by using the shallow copy method share the data of the reference type, so if the reference type data in the new object is modified, the original object will also be affected, and the deep copy will completely copy an object, and the new object and the original object There is no relationship, so any modification of the reference type data in the new object will not affect the original object. Therefore, deep copies are more reliable than shallow copies when dealing with nested data structures.

Fourth, the method of implementing shallow copy and deep copy

1. Shallow copy

1-1.slice()

The Array.prototype.slice() method can copy a part of the elements in the array to a new array. This method is a shallow copy because it only copies the reference of the object instead of the object itself. It can be seen that after modifying the value of the copied object arr2, the value of the original object arr1 is also changed.

let arr1 = [1, 2, { a: 3, b: {c: 4}}];
let arr2 = arr1.slice();
console.log(arr1); //[ 1, 2, { a: 3, b: { c: 4 } } ] 
console.log(arr2); //[ 1, 2, { a: 3, b: { c: 4 } } ] 
arr2[2].b.c = 666;
let arr3 = arr1.slice();
console.log(arr1); //[ 1, 2, { a: 3, b: { c: 666 } } ]
console.log(arr3); //[ 1, 2, { a: 3, b: { c: 666 } } ]

1-2.concat()

The Array.prototype.concat() method can copy some of the elements in the array to a new array, or combine multiple arrays into a new array. This method is a shallow copy because it only copies the object's reference and not the object itself. It can be seen that after modifying the value of the copied object arr2, the value of the original object arr1 is also changed.

let arr1 = [1, 2, { a: 3, b: {c: 4}}];
let arr2 = [].concat(arr1);
// let arr2 = arr1.concat();
console.log(arr1); //[ 1, 2, { a: 3, b: 4 } ]
console.log(arr2); //[ 1, 2, { a: 3, b: 4 } ]
arr2[2].b.c = 666;
let arr3 = arr1.concat();
console.log(arr1); //[ 1, 2, { a: 3, b: { c: 666 } } ]
console.log(arr3); //[ 1, 2, { a: 3, b: { c: 666 } } ]

1-3.Object.assign()

The Object.assign() method can shallow copy the properties of multiple objects. Shallow copy just copies the reference of the object, not the object itself. It can be seen that after modifying the value of the copied object obj2, the value of the original object obj1 is also changed.

let obj1 = { a: 1, b: {c: 2}};
let obj2 = Object.assign({}, obj1);
console.log(obj1);   //{ a: 1, b: { c: 2 } }
console.log(obj2);   //{ a: 1, b: { c: 2 } }
console.log(obj2.b); //{ c: 2 }
obj2.b.c = 666;
console.log(obj1);   //{ a: 1, b: { c: 666 } }
console.log(obj2);   //{ a: 1, b: { c: 666 } }
console.log(obj2.b); //{ c: 666 }

1-4.Object.create()

The Object.create() method can use an object as a prototype to create a new object. The new object is a shallow copy of the properties of the prototype object, that is, only the reference to the object is copied instead of the object itself. It can be seen that after modifying the value of the copied object obj2, the value of the original object obj1 is also changed.

let obj1 = { a: 1, b: {c: 2}};
let obj2 = Object.create(obj1);
console.log(obj1);   //{ a: 1, b: { c: 2 } }
console.log(obj2);   //{}
console.log(obj2.a); //1
console.log(obj2.b); //{ c: 2 }
obj2.b.c = 666;
console.log(obj1);   //{ a: 1, b: { c: 666 } }
console.log(obj2);   //{}
console.log(obj2.a); //1
console.log(obj2.b); //{ c: 666 }

The Object.create() method creates a new object whose prototype is the specified object. The new object inherits the properties of the parameter object, but it has no properties and methods, so it looks like an empty object, so strictly speaking, it may not be a shallow copy, this method 仅供参考.

1-5. Spread operator(...)

The spread operator can expand an object into multiple separate properties, which is equivalent to a shallow copy, which also copies the object reference instead of the object itself. It can be seen that after modifying the value of the copied object obj2, the value of the original object obj1 is also changed.

let obj1 = { a: 1, b: {c: 2}};
let obj2 = { ...obj1 };
console.log(obj1);   //{ a: 1, b: { c: 2 } }
console.log(obj2);   //{ a: 1, b: { c: 2 } }
console.log(obj2.b); //{ c: 2 }
obj2.b.c = 666;
console.log(obj1);   //{ a: 1, b: { c: 666 } }
console.log(obj2);   //{ a: 1, b: { c: 666 } }
console.log(obj2.b); //{ c: 666 }

2. Deep copy

2-1.JSON.parse(JSON.stringify())

The implementation of this method is to convert the object into a JSON string first, and then convert the JSON string back to the object, so that the object or array can be completely copied, and all data are basic type data, and there is no mutual influence of reference type data The problem.

let obj = {
    fruit: '水果',
    type: {
      one: {
        name: '哈密瓜',
        price: 10
      },
      two: {
        name: '西瓜',
        price: 20,
        date: new Date(),
        regexp: /^B/,
        birth: undefined
      },
      three: {
        name: Symbol("荔枝"),
        price: 30
      }
    }
};
let obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2);
// {
//     fruit: '水果',
//     type: {
//       one: { name: '哈密瓜', price: 10 },
//       two: {
//         name: '西瓜',
//         price: 20,
//         date: '2023-06-14T02:50:07.911Z',
//         regexp: {}
//       },
//       three: { price: 30 }
//     }
//  }
obj2.type.one.name = "蓝莓"; //修改拷贝对象,看原对象会不会改变
console.log(obj);
// {
//     fruit: '水果',
//     type: {
//       one: { name: '哈密瓜', price: 10 },
//       two: {
//         name: '西瓜',
//         price: 20,
//         date: 2023-06-14T02:52:16.530Z,
//         regexp: /^B/,
//         birth: undefined
//       },
//       three: { name: Symbol(荔枝), price: 30 }
//     }
//  }

But it should be noted that this method has 缺陷.

  1. Special objects such as 函数and cannot be copiedRegExp正则表达式
  2. unhandled 循环引用situation
  3. Attributes that cannot be copied undefinedand symboltyped
  4. Types in objects Dateare converted to strings
  5. object contains NaN, Infinitywill become null

Five, handwriting to achieve deep copy and shallow copy

1. Shallow copy

// 简陋版浅拷贝
function shallowCopy(obj) {
  // 判断是否是对象或者数组
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  // 判断当前属性是数组还是对象
  let newObj = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 复制属性值
      newObj[key] = obj[key];
    }
  }
  return newObj;
}

2. Deep copy

2-1 Method 1

// 简陋版深拷贝
function deepCopy(obj) {
  // 如果obj是null,则直接返回
  if(obj === null){
    return null;
  }
  // 如果obj不是对象或数组,则直接返回
  if(typeof obj !== 'object'){
    return obj;
  }
  if (obj instanceof RegExp) return new RegExp(obj);// 处理正则表达式
  if (obj instanceof Date) return new Date(obj);    // 处理日期对象
  // 判断obj是数组还是对象
  let newObj = Array.isArray(obj) ? [] : {};
  // 遍历对象或数组的所有属性或元素
  // 判断是否是显示具有的属性,而不是从原型上继承得到的属性
  for(let key in obj){
    if(Object.prototype.hasOwnProperty.call(obj, key)) {
      // Reflect.ownKeys(obj)
      // 如果属性或元素还是对象或数组,则递归调用深拷贝函数
      newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
    }
  }
  return newObj;
}

2-2 Method 2

The MessageChannel interface allows us to create a new message channel and send data through its two MessagePort properties.

function deepCopy(obj) {
  return new Promise((resolve, reject) => {
    // 创建一个新的 MessageChannel 对象,并获取两个端口 port1 和 port2
    const { port1, port2 } = new MessageChannel(); 
    // 将要拷贝的对象通过 port1 发送出去
    port1.postMessage(obj); 
    // 监听 port2 收到的消息
    port2.onmessage = (msg) => { 
    // 当 port2 收到消息时,将消息的数据作为 Promise 的结果进行 resolve
      resolve(msg.data); 
    }
  })
}
deepCopy(obj).then(res => {
  console.log(res);
})

6. Final Words

There is no difference between deep copy and shallow copy, high-level and low-level, just use the appropriate method in different demand scenarios.

The ability is average and the level is limited. There may be omissions or mistakes in this article. If you have any questions, please correct me. Thank you for reading this article. If you think the writing is okay, don’t forget to like, comment, and bookmark! I wish you all a happy life!

Front-end and back-end interview question banks (necessary for interviews) Recommended: ★★★★★

Address: front-end interview question bank   web front-end interview question bank VS java back-end interview question bank Daquan

Guess you like

Origin blog.csdn.net/weixin_42981560/article/details/131694642