zoukankan      html  css  js  c++  java
  • js变量浅拷贝 深拷贝

    js的变量分为简单数据类型和复杂数据类型(即引用类型)。

    简单数据类型在内存中占据着固定大小的空间,被保存在栈内存中,在简单数据类型中,当一个变量指向另一个变量时,只是创建了值的副本,两个变量只是占用的空间大小相同,值相同,但是存储的位置不同。因此,当其中一个值改变的时候,不会对另一个值有影响。

    对于引用类型,值是对象,保存在堆内存中。当一个变量指向另一个变量时,它们其实指向的是同一个内存空间,变量保存的是指向实际对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针地址而已,因此两个变量最终都指向同一个对象。

    引用类型:

    var obj1={name:'sally'};
    var obj2=obj1;
    obj2.age=9;
    
    console.log(obj1)
    //{name: "sally", age: 9}
    console.log(obj2)
    {name: "sally", age: 9}
    
    

    obj赋值给obj2后,改变其中一个对象的属性值,两个对象都发生了改变,根本原因就是obj和obj2两个变量都指向同一个指针,赋值时只是复制了指针地址,它们指向同一个引用。

    1、浅拷贝

    以上就是简单的浅拷贝的例子,但是改变任一变量都会互相影响。

    2、深拷贝

    深拷贝就是完全复制变量的一份给其他的变量备份。解决浅拷贝带来的问题;

    1、数组
    (1)只包含简单数据类型的数组

    对于仅仅包含简单数据类型的数组来说可以使用slice和concat来实现;
    如:
    var a = b.slice(0);
    var b = [].concat(b);//或者b.concat();

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

    如:

    var a=[1,3,4,[46,23]];
    var b = a.slice(0);
    b[3][0]='34';
    console.log(a,b)
    //a、b均为[1,3,4,[34,23]
    

    可见,当改变b[3].name的时候,a也会被改变。解决次问题可以定义以下函数:

    function deepCopyArray(arr){
        var output = arr.slice(0);
        for(var index=0;index<output.length;index++){
            if(Object.prototype.toString.call(output[index])==='[object Array]'){
               output[index]=copyArray(output[index]);
            } 
            
        }
        return output;
    }
    
    2、对象

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

    如:

    var a={name:'sally',age:26};
    var b={};
    b.name = a.name;
    b.age = a.age;
    b.hobby = 'sing'
    console.log(a); //{name: "sally", age: 26}
    console.log(b); //{name: "sally", age: 26, hobby: "sing"}
    

    如果对象中属性值仅仅是简单数据类型,遍历源对象的属性,将对应的属性值赋给最后的对象即可,如果源对象中的属性值是对象的话就需要通过递归来实现了。

    如下实现的对象深拷贝函数:

    function deepCopyObject(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;
    }
    
    3、数组对象混合的通用深拷贝函数
    function deepCopy(input){
        var output;
        if(Object.prototype.toString.call(input)==='[object Array]'){
           output = input.slice(0);
        } 
        if(Object.prototype.toString.call(input)==='[object Object]'){
           output = {};
           for(let key in input) {   
                output[key] = input[key]
           } 
        } 
        for(let key in output){
            if(typeof output[key]==='object'){
                output[key]=deep(output[key]);
            }
        }
        return output;
    }
    

    验证代码

    (1)数组包含数组元素
    var a=[1,3,4,[46,23]];
    var b = deep(a);
    b[3][0]=34;
    console.log(a,b)
    

    (2)数组包含数组和对象
    var a=[1,3,4,[46,23],{name:'sally'}];
    var b = deep(a);
    b[3][0]=34;
    b[4].name='bob';
    console.log(a,b)
    

    (3)对象包含对象
    var a={name:'sally',list:{num:[1,2,3,4]}};
    var b = deep(a);
    b.list.num[2]=34;
    b.name='bob';
    console.log(a,b)
    

    (4)对象包含数组
    var a={name:'sally',list:[1,2,3,4]};
    var b = deep(a);
    b.list[0]=34;
    b.name='bob';
    console.log(a,b)
    

  • 相关阅读:
    [PoC]某B2B网站的一个反射型XSS漏洞
    Python中的基本语句
    视频: 千重浪Linux系统调试技术培训 03-01_Basic-CPU-Register
    POJ 2955 Brackets (区间dp 括号匹配)
    LeetCode 146 LRU Cache
    Poj1734题解
    Python
    小胖说事29-----iOS中Navigation中左滑pop页面的三种方法
    深入理解javascript之原型
    android 弹幕评论效果
  • 原文地址:https://www.cnblogs.com/csuwujing/p/9804746.html
Copyright © 2011-2022 走看看