Home  >  Article  >  Web Front-end  >  JavaScript Topic 5: Deep and Shallow Copy

JavaScript Topic 5: Deep and Shallow Copy

coldplay.xixi
coldplay.xixiforward
2021-03-08 09:36:141929browse

JavaScript Topic 5: Deep and Shallow Copy

Understand the process behind copying and avoid unnecessary mistakes. Let’s work together on the deep and shallow copying of Js special series~

Contents

  • 1. Copy example
  • 2. Shallow copy
  • 3. How to deep copy?
  • 4. Implement deep and shallow copy by yourself

Free learning recommendation: javascript video tutorial

1. Copy example

When we operate the data, we may encounter the following situation:

  1. A set of data will be changed frequently, but the original data may be used
  2. I need two sets of the same data, but I don’t want to change one and the other will change
  3. I It is necessary to compare the data before and after the operation

When we encounter similar need scenarios, the first thing that comes to mind is to copy it, but we don’t know that copying also has a lot of knowledge~

Does the following simple example sound familiar to you?

1.1 Basic type copy example
var str = 'How are you';var newStr = str;newStr = 10console.log(str); // How are youconsole.log(newStr); // 10

As everyone can imagine, string is a basic type, and its value is stored in the stack. When copying it, it is actually opening up new variables. new space. str and newStr are like two identical rooms, with the same layout but no connection.

1.2 Reference type copy example
var data = [1, 2, 3, 4, 5];var newData = data;newData[0] = 100;console.log(data[0]); // 100console.log(newData[0]); // 100

Similar code segment, but this time we use the reference type of array as an example. You will find that after modifying the assigned data, the original data has also changed. This obviously doesn't meet our needs. This article will talk about the knowledge of quoting data copy.

If you have questions about the data types of Js, you might as well take a look at "Basic Data Types in JavaScript"

JavaScript Topic 5: Deep and Shallow Copy

2. Shallow copy

The division of copies is discussed based on reference types. Shallow copy - as the name suggests, shallow copy is a "shallow copy". In fact, it only does superficial work:

var arr = [1, 2, 3, 4];var newArr = arr;console.log(arr, newArr); // [1,2,3,4] [1,2,3,4]newArr[0] = 100;console.log(arr, newArr) // [100,2,3,4] [100,2,3,4]

Fortunately, nothing happens (operation). Once the new array is operated on, the data stored in both variables will change.

The reason why this kind of situation occurs is also because of the basic characteristics of reference type:

  • The value stored in the variable is a pointer (point), pointing to the storage The memory address of the object. Assigning a value to a new variable is equivalent to assigning a new key, and the room has not been changed.

Both slice and concat in the array will return a new array. Let’s try it together:

var arr = [1,2,3,4];var res = arr.slice();// 或者res = arr.concat()res[0] = 100;console.log(arr); // [1,2,3,4]

Is this problem solved so quickly? Although this layer of data is processed in this way, the problem is indeed solved, but!

var arr = [ { age: 23 }, [1,2,3,4] ];var newArr = arr.concat();arr[0].age = 18;arr[1][0] = 100;console.log(arr) // [ {age: 18}, [100,2,3,4] ]console.log(newArr) // [ {age: 18}, [100,2,3,4] ]

Sure enough, things are not that simple, this is also because of the different data types.

S ​​We are not allowed to directly operate the address in the memory, which means that we cannot operate the memory space of the object. Therefore, our operations on the object are only operating on its reference.

Since shallow copy cannot meet our requirements, based on the principle of efficiency, we are looking to see if there is anyone who can help us achieve deep copy Methods.

JavaScript Topic 5: Deep and Shallow Copy

#3. How to deep copy?

The data method failed, is there any other way? We need to achieve a true copy of independent data.

3.1 JSON

Here we use two methods of JSON, JSON.stringify(), JSON.parse() to achieve the most concise Deep copy

var arr = ['str', 1, true, [1, 2], {age: 23}]var newArr = JSON.parse( JSON.stringify(arr) );newArr[3][0] = 100;console.log(arr); // ['str', 1, true, [1, 2], {age: 23}]console.log(newArr); // ['str', 1, true, [100, 2], {age: 23}]

This method should be the simplest way to implement deep copy, but it still has problems, let’s take a look at what we just did:

  1. Define an array containing all typesarr
  2. JSON.stringify(arr), convert a JavaScript object or value into a JSON string
  3. JSON.parse(xxx), method is used to parse JSON strings and construct values ​​or objects described by strings

Understand :

We can understand that the original data is converted into new string, and then restored to a new object# through new string ##, the method of changing the data type indirectly bypasses the process of copying the object reference, and does not affect the original data.

Restrictions:

The fundamental purpose of this method is to ensure the integrity of the data during "transfer", and

JSON.stringify() There are also flaws in converting values ​​to the corresponding JSON format:

  • undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。
  • 函数、undefined 被单独转换时,会返回 undefined,
    • 如JSON.stringify(function(){})
    • JSON.stringify(undefined)
  • 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
  • NaN 和 Infinity 格式的数值及 null 都会被当做 null。
  • 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。

所以当我们拷贝函数、undefined等stringify转换有问题的数据时,就会出错,我们在实际开发中也要结合实际情况使用。

举一反三:

既然是通过改变数据类型来绕过拷贝引用这一过程,那么单纯的数组深拷贝是不是可以通过现有的几个API来实现呢?

var arr = [1,2,3];var newArr = arr.toString().split(',').map(item => Number(item))newArr[0] = 100;console.log(arr); // [1,2,3]console.log(newArr); // [100,2,3]

注意,此时仅能对包含纯数字的数组进行深拷贝,因为:

  1. toString无法正确的处理对象和函数
  2. Number无法处理 false、undefined等数据类型

但我愿称它为纯数字数组深拷贝

JavaScript Topic 5: Deep and Shallow Copy

3.2 Object.assign()

有的人会认为Object.assign(),可以做到深拷贝,我们来看一下

var obj = {a: 1, b: { c: 2 } }var newObj = Object.assign({}, obj)newObj.a = 100;newObj.b.c = 200;console.log(obj); // {a: 1, b: { c: 200 } }console.log(newObj) // {a: 100, b: { c: 200 } }

神奇,第一层属性没有改变,但第二层却同步改变了,这是为什么呢?

因为 Object.assign()拷贝的是(可枚举)属性值。

假如源值是一个对象的引用,它仅仅会复制其引用值。MDN传送门

四、自己实现深浅拷贝

既然现有的方法无法实现深拷贝,不妨我们自己来实现一个吧~

4.1 浅拷贝

我们只需要将所有属性即其嵌套属性原封不动的复制给新变量一份即可,抛开现有的方法,我们应该怎么做呢?

var shallowCopy = function(obj) {
    if (typeof obj !== 'object') return;

    // 根据obj的类型判断是新建一个数组还是对象
    var newObj = obj instanceof Array ? [] : {};
    // 遍历obj,并且判断是obj的属性才拷贝
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;}

我们只需要将所有属性的引用拷贝一份即可~

4.2 深拷贝

相信大家在实现深拷贝的时候都会想到递归,同样是判断属性值,但如果当前类型为object则证明需要继续递归,直到最后

var deepCopy = function(obj) {
    if (typeof obj !== 'object') return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj;}

我们用白话来解释一下deepCopy都做了什么

const obj = [1, { a: 1, b: { name: '余光'} } ];const resObj = deepCopy(obj);
  • 读取 obj,创建 第一个newObj
    • 判断类型为 []
    • key为 0 (for in 以任意顺序遍历,我们假定按正常循序遍历)
    • 判断不是引用类型,直接复制
    • key为 1
    • 判断是引用类型
    • 进入递归,重新走了一遍刚才的流程,只不过读取的是obj[1]

另外请注意递归的方式虽然可以深拷贝,但是在性能上肯定不如浅拷贝,大家还是需要结合实际情况来选择。

写在最后

JavaScript Topic 5: Deep and Shallow Copy

前端专项进阶系列的第五篇文章,希望它能对大家有所帮助,如果大家有什么建议,可以在评论区留言,能帮到自己和大家就是我最大的动力!

相关免费学习推荐:javascript(视频)

The above is the detailed content of JavaScript Topic 5: Deep and Shallow Copy. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete