• 深入理解JavaScript的深拷贝和浅拷贝


    为了更好的理解js的深浅拷贝,我们先来理解一些js基本的概念 —— Javascript有五种基本数据类型(也就是简单数据类型),它们分别是:Undefined,Null,Boolean,Number和String。还含有一种复杂的数据类型(也叫引用类型),就是对象

     注意Undefined和Null的区别,Undefined类型只有一个值,就是undefined,Null类型也只有一个值,也就是null

     

    Undefined 其实就是已声明未赋值的变量输出的结果

    null 其实就是一个不存在的对象的结果

    var a;
    console.log(a)//undefined
    
    console.log(document.getElementById('asdd'))//没有id为asdd的节点,输出null

    基本数据类型与引用数据类型

    1. 对于基本数据类型

    他们的值在内存中占据着固定大小的空间,并被保存在栈内存中。当一个变量向另一个变量复制基本类型的值,会创建这个值的副本,并且我们不能给基本数据类型的值添加属性

    var x = 1;
    var y = x;
    x.name = 'hanna';
    console.log(y); //1
    console.log(x.name); //undefined

    上面的代码中,x是基本数据类型(Number), y是x的一个副本,它们两者都占有不同位置但相等的内存空间,只是它们的值相等,若改变其中一方,另一方不会随之改变。

    2. 对于引用类型

    复杂的数据类型即是引用类型,它的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针地址而已,因此两个变量最终都指向同一个对象

    var obj = {
       name:'Hanna Ding',
       age: 22
    }
    var obj2 = obj;
    obj2['c'] = 5;
    console.log(obj); //Object {name: "Hanna Ding", age: 22, c: 5}
    console.log(obj2); //Object {name: "Hanna Ding", age: 0, c: 5}

    我们可以看到obj赋值给obj2后,但我们改变其中一个对象的属性值,两个对象都发生了改变,根本原因就是obj和obj2两个变量都指向同一个指针,赋值时只是复制了指针地址,它们指向同一个引用,所以当我们改变其中一个的值就会影响到另一个变量的值。

    01 浅拷贝

     其实上面那段代码就是浅拷贝,有时候我们只是想备份数组,但是只是简单让它赋给一个变量,改变其中一个,另外一个就紧跟着改变,但很多时候这不是我们想要的

    var arr = [1, 2, 3, '4'];
    
    var arr2 = arr;
    arr2[1] = "test"; 
    console.log(arr); // [1, "test", 3, "4"]
    console.log(arr2); // [1, "test", 3, "4"]

    02 深拷贝

    (1)数组

    对于数组我们可以使用slice() 和 concat() 方法来解决上面的问题

    slice 

    var arr = ['a', 'b', 'c'];
    var arrCopy = arr.slice(0);
    arrCopy[0] = 'test'
    console.log(arr); // ["a", "b", "c"]
    console.log(arrCopy); // ["test", "b", "c"]

    concat

    var arr = ['a', 'b', 'c'];
    var arrCopy = arr.concat();
    arrCopy[0] = 'test'
    console.log(arr); // ["a", "b", "c"]
    console.log(arrCopy); // ["test", "b", "c"]

    知识点补充:

    • arrayObj.slice(start, [end]) 该方法返回一个 Array 对象,其中包含了 arrayObj 的指定部分。不会改变原数组
    • arrayObj.concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

    其实也就是下面这么个意思。。。但还是用上面的方法来实现比较简单高效些

    function deepCopy(arr1, arr2) {
       for (var i = 0; i < arr1.length; ++i) {
           arr2[i] = arr1[i];
       }
    }

    (2)对象

    对象的深拷贝实现原理: 定义一个新的对象,遍历源对象的属性 并 赋给新对象的属性

    var obj = {
       name:'Hanna Ding',
       age: 22
    }
    
    var obj2 = new Object();
    obj2.name = obj.name;
    obj2.age = obj.age
    
    obj.name = 'xiaoDing';
    console.log(obj); //Object {name: "xiaoDing", age: 22}
    console.log(obj2); //Object {name: "Hanna Ding", age: 22}

    理解了以上的基本思想,我们就可以封装一个方法 deepCopy来实现对象的深拷贝,代码如下

    var obj = {
        name: 'Hanna',
        age: 22
    }
    var deepCopy = function (source) {
        var result = {};            
        for(var key in source) {                
            if(typeof source[key] === 'object') {
                result[key] = deepCopy(source[key])
            } else {
                result[key] = source[key]
            }
        }            
        return result;
    }
    
    var objCopy = deepCopy(obj)
    obj.name = 'ding';
    console.log(obj);//Object {name: "ding", age: 22}
    console.log(objCopy);//Object {name: "Hanna", age: 22}
    本文为 小丁码园 作者HannaDing原创文章,如需转载请注明原文网址摘自http://www.cnblogs.com/dinghuihua/
  • 相关阅读:
    微信小程序如何获取openid
    js经典试题之常用的方法
    js经典试题之运算符的优先级
    js如何使浏览器允许脚本异步加载
    es6从零学习(五):Module的语法
    es6从零学习(四):Class的继承
    js如何处理字符串中带有↵字符
    Zuul中聚合Swagger的坑
    阿里Sentinel支持Spring Cloud Gateway啦
    Spring Boot中的Mongodb多数据源扩展
  • 原文地址:https://www.cnblogs.com/dinghuihua/p/6674719.html
Copyright © 2020-2023  润新知