深拷贝与浅拷贝

深拷贝和浅拷贝主要是针对引用类型的值的赋值(或复制)操作。

一、区分基本类型和引用类型

基本类型的值引用类型的值
Undefined,Null,Boolean,String,NumberObject,Array,Date,RegExp,Function
按值访问(可以操作保存在变量中的实际的值)按引用访问(操作对象时,实际上是操作对象的引用)
保存在变量中的实际的值保存在内存中的对象(不允许直接访问)
赋值时,前后两个变量时独立的赋值时,前后两个变量指向内存中的同一位置(引用类型的实际值存放在堆中)
对于向函数传参,都是按值传递(但是引用类型的传参有点特别,如果不是重写,那么参数和外面的变量都是指向同一个堆位置,如果重写了,那参数就指向一个新创建的局部变量,原对象无影响,这说明不是按引用传递)

检测类型的方法

1、使用typeof,可区分出string,number,boolean,undefined,object,function等

2、使用instanceof :obj instanceof Object,如果是引用类型则返回 true,否则返回false。

二、基本类型的赋值(或复制)

例一:

var num1 = 1;
var num2 = num1;  //num2 = 1
num2 = 2;  //num2 = 2,num1 = 1

复制前的变量对象

 

 

 

 

Num1

1(Number类型)

复制后的变量对象

 

 

Num2

1(Number类型)

Num1

1(Number类型)

基本类型的赋值操作后的两个变量,是独立的,改变num2的值,不会影响到num1。

三、引用类型的赋值(或复制)

例二:

var obj1 = {
    name : 'zsx',
    age : 10
}
var obj2 = obj1;  //obj1 = {name: "zsx", age: 10},obj2 = {name: "zsx", age: 10}
obj2.name = 'changeName';  //obj1 = {name: "changeName", age: 10},obj2 = {name: "changeName", age: 10}

复制前的变量对象

 

 

 

 

Obj1

堆地址1:指向存储在堆中的一个对象(Object类型)

复制后的变量对象

 

 

Obj2

堆地址1:指向存储在堆中的一个对象(Object类型)

Obj1

堆地址1:指向存储在堆中的一个对象(Object类型)

堆内存

引用类型的赋值操作,其实复制的是指针,相同的指针使得前后两个变量指向的对象一致,因此改变obj2,会反映到obj1。

例三:

var arr1 = [1,2,3];
var arr2 = arr1;  //arr1 = [1, 2, 3],arr2 = [1, 2, 3]
arr2[0] = 0;  //arr1 = [0, 2, 3],arr2 = [0, 2, 3]

例四:

var array=[];
var item={};
for(var i=0;i<5;i++){    
    item.a=i;   //在这里,修改的都是堆中同一个位置的对象,因此array中的元素都指向同一个item   
    array.push(item);   
}
console.log(array);  // [ { a: 4 }, { a: 4 }, { a: 4 }, { a: 4 }, { a: 4 } ]

for(var i=0;i<5;i++){    
    var item={};   //在这里,每次都新建一个对象,array中的元素指向五个不同的item 
    item.a=i;    
    array.push(item);   
} //[ { a: 0 }, { a: 1 }, { a: 2 }, { a: 3 }, { a: 4 } ]

四、引用类型的浅拷贝

//浅拷贝实现
function shallowCopy (obj) {
    var newObj = {};
    for(let key in obj) {
        if(obj.hasOwnProperty(key)) {
            newObj[key] = obj[key]; //复制obj拥有的直接属性
        }
    }
    return newObj;
}

例五:

var arr1 = [1,{a:2},[3,4]];
var arr2 = arr1.slice(0);  //arr1 =  [1,{a:2},[3,4]],arr2 = [1,{a:2},[3,4]]
arr2[0] = 0;  //arr1 =  [1,{a:2},[3,4]],arr2 = [0, {a:2}, Array(2)],浅拷贝
arr2[1].a = 22;  //arr1 =  [1,{a:22},[3,4]],arr2 = [1,{a:22},[3,4]],元素中的对象是赋值操作
arr2[2][0] = 33;  //arr1 =  [1,{a:2},[33,4]],arr2 = [1,{a:2},[33,4]] ,元素中的数组是赋值操作

例六:

var arr1 = [1,{a:2},[3,4]];
var arr2 = arr1.concat();  //arr1 =  [1,{a:2},[3,4]],arr2 = [1,{a:2},[3,4]]
arr2[0] = 0;  //arr1 =  [1,{a:2},[3,4]],arr2 = [0, {a:2}, Array(2)],浅拷贝
arr2[1].a = 22;  //arr1 =  [1,{a:22},[3,4]],arr2 = [1,{a:22},[3,4]],元素中的对象是赋值操作
arr2[2][0] = 33;  //arr1 =  [1,{a:2},[33,4]],arr2 = [1,{a:2},[33,4]] ,元素中的数组是赋值操作

例七:

var obj1 = {
    name : 'zsx',
    friend : {
        name : 'xiaohong',
        age : 12
    }
}
var obj2 = Object.assign({}, obj1);  //obj1 = {name: "zsx", friend: {name: "zsx", age: 12}},obj2 = {name: "zsx", friend: {name: "zsx", age: 12}}
obj2.friend.name = 'changeName';  //obj1 = {name: "zsx", friend: {name: "changeName", age: 12}},obj2 = {name: "zsx", friend: {name: "changeName", age: 12}},浅拷贝 

无论是利用slice、concat和Object.assign(),都是浅拷贝,子对象(子数组)是赋值操作。

五、引用类型的深拷贝

例八:利用递归进行深拷贝

//简单版深拷贝函数
function deepCopy (obj) {
    //如果需要拷贝的obj是null,不是数组或者对象,则直接返回obj
    if (obj === null || typeof obj !== 'object') {
        return obj
    }
    var copy = Array.isArray(obj) ? [] : {};  //判断是对象还是数组

    //通过Object.keys(obj)的方法,从obj中获取一个key数组
    //注意:Object.keys(obj)不遍历原型链
    Object.keys(obj).forEach(key => {
        copy[key] = deepCopy(obj[key]);
    });

    return copy;
}
var obj1 = {
    name : 'zsx',
    friend : {
        name : 'xiaohong',
        age : 12
    }
}
var obj2 = deepCopy(obj1);  //obj1 = {name: "zsx", friend: {name: "xiaohong", age: 12}},obj2 = {name: "zsx", friend: {name: "xiaohong", age: 12}}
obj2.friend.name = 'changeName';  //obj1 = {name: "zsx", friend: {name: "xiaohong", age: 12}},obj2 = {name: "zsx", friend: {name: "changeName", age: 12}}

例九:利用JSON.stringify()和JSON.parse()进行深拷贝

var obj1 = {
    name : 'zsx',
    friend : {
        name : 'xiaohong',
        age : 12
    }
}
//利用JSON.stringify()方法将obj1转换为字符串,将字符串赋值给obj2
var obj2 = JSON.stringify(obj1); 
//再利用JSON.parse()方法解析json,重新分配空间给obj2
obj2 = JSON.parse(obj2);
obj2.friend.name = 'changeName';  //obj1 = {name: "zsx", friend: {name: "xiaohong", age: 12}},obj2 = {name: "zsx", friend: {name: "changeName", age: 12}}

六、区分赋值(=)、浅拷贝和深拷贝

赋值(=):只赋值引用类型整体的地址。

浅拷贝:复制对象(数组)的直接元素,子对象(子数组)进行赋值操作。

深拷贝:复制对象(数组)中的属性(元素),包括子对象(子数组)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值