js中的深浅拷贝

109 阅读3分钟

基本类型&引用类型

JavaScript中数据类型可以分为两类:基本类型和引用类型

  • 基本类型:string,number,symbol,undefined,null,Boolean
  • 引用类型:Array,Function,Object,Date

基本数据类型保存在栈内存中,有固定的内存空间大小存储;而引用类型保存在堆内存中,它存放的是变量在堆中的内存地址,这个地址指向的是数据。

因为基本类型有可以计算出固定的大小,可以合理的分配合适大小的内存空间,所以它被保存在栈中;而函数,数组这一类数据定义了,函数可以无限扩展,数据可以无限添加,无法确定其大小空间,所以被保存在堆中,通过地址链接到这个数据.这里我们就可以知道在浅拷贝中如果复制出来的数据修改了值,那么原始的值也会改变,因为我们浅拷贝就是复制了对这个数据的引用地址,而不是真正的开辟内存空间保存这个数据.

浅拷贝

现在我们知道了如果一个数据不是引用类型,我们就可以通过浅拷贝的方法.

var person = "tom"
var newperson = person

我们针对基本的数据类型通过赋值操作就是能直接拷贝,那么如果是引用类型里浅拷贝呢?

var person = {
    name: "tom",
    age: 18,
    hobby: {
        num: 3
    }
}
//上面我们定义了一个person,我们可以用遍历的方式来进行浅拷贝
function copy(obj){
    var newobj = {}//定义新的对象接受
    for(key in obj){
    //只复制它背身有的属性
        newobj[key] = obj[key]
    }
    return newobj
}
//我们定义了一个copy函数
var newperson = copy(person)

通过上面循环的方式我们就完成了一个对象的浅拷贝,当我们修改新对象上的age属性时,原对象的age不会改变;但是当我们修改hoobby中num属性时,原对象的num同样也就修改了.

当有深层的引用类型时,我们通过浅拷贝无法满足我们的需求,因为它仅仅是拷贝了一个引用的地址,实际新旧两对象是指向的同一个数据,当其中一个数据修改,另一个数据也体现出来了.那我们再看下深拷贝.

深拷贝

深拷贝我们一般常用的有两种,JSON和递归

JSON方式

var person = {
    name: "tom",
    age: 18,
    hobby: {
        num: 3
    }
}

var newperson = JSON.parse(JSON.stringify(person))

我们先通过JSON.stringify()方式将对象先转换为字符串,再通过JSON.parse()转换为对象.这个方法虽然好用,但也有它的不足.

var person = {
    a: undefined,
    b:null,
    c:function(){
        alert("1")
    },
    name: "tom",
    age: 18,
    hobby: {
        num: 3
    }
}

var newperson = JSON.parse(JSON.stringify(person))

上面我们定义了a,b,c三个属性,通过打印结果看来,undefinedfunction,都被过滤掉了.虽然它有不足,但在日常使用中已经足够了.

递归的方法

var person = {
    a: undefined,
    b:null,
    c:function(){
        alert("1")
    },
    name: "tom",
    age: 18,
    hobby: {
        num: 3
    }
}

function deepcopy(obj){
    var newobj = null 
    //定义变量用来存贮拷贝后的内容 
    if(typeof obj === "object" && obj !== null){
    //先判断下拷贝的函数是不是对象并且不为null
        newobj = obj instanceof Array? []: {}
        //判断是数组还是对象,复制
        for(var i in obj){
            循环遍历每一项,直到没有复杂数据类型
            newobj[i] = deepcopy(obj[i])
        }
    }else{
         newobj = obj 
    }
    return newobj
}