浅拷贝深拷贝和个人一些新理解(非普遍的理解)

76 篇文章 2 订阅
18 篇文章 1 订阅

预备知识

  • 引用数据类型

    • Object(在JS中除了基本数据类型以外的都是对象,数据是对象,函数是对象等等)
  • 基本数据类型

    • NumberStringBooleanNullUndefinedSymbol
  • 文章参考了牛客网CodeSheep

赋值 vs 浅拷贝 vs 深拷贝

赋值(不能算是拷贝,因为拷贝的仅仅只是引用关系,并没有生成新的实际对象)

很常见的一种

var a = 10;
var b = 100;
var obj = {
    name:"李白",
    sex:"男"
}
// 注意,这个严格来说是赋值,不是什么浅拷贝深拷贝!后面有原因
var obj2 = obj;

// 注意,这个严格来说是赋值,不是什么浅拷贝深拷贝
Student codeSheep = new Student();
Student codePig = codeSheep;

浅拷贝

一个误区

很多人说var objOrigin = {name:'李白'}; var objAfter = objOrigin; 是浅拷贝,严格来说是错误的!

// 严格来说是错误的!
// 如果说下面这一行是浅拷贝
var objOrigin = {name:'李白'}; var objAfter = objOrigin;是浅拷贝

//那么这个是什么?
var obj1 = { name: '李白', sex: '男' };

var clonedObj = { ...obj1 };
clonedObj.name="李黑";

console.log(clonedObj); // {name: '李黑', sex: '男'}

console.log(obj1);// {name: '李白', sex: '男'}

//可以看到,克隆后的对象将名字修改为了李黑,原来的没有变化
  • 这里使用了展开运算符(扩展运算符),官方解释是浅拷贝

  • 如果按照之前有些人的说法,下面这个是浅拷贝

    var objOrigin = {name:'李白'}; var objAfter = objOrigin;
    
    • 那么mdnWebDocs当中的展开运算符(扩展运算符)可以实现浅拷贝,那么按道理来说这个所谓的浅拷贝,修改了浅拷贝后的对象不会导致原来的对象改变吧?那为什么修改后会发生改变?

      //var objOrigin = {name:'李白'}; var objAfter = obj;是浅拷贝
      
      var objOrigin = {name:'李白'}; 
      var objAfter = objOrigin;
      //修改拷贝后的对象当中的name(name为基本数据类型)
      objAfter.name="李黑";
      
      //输出为 {name: '李黑'}
      console.log(objAfter);
      
      //输出为 {name: '李黑'}
      console.log(objOrigin);
      
      
    • 所以觉得,赋值就是赋值,不是什么浅拷贝和深拷贝!不然你说var objAfter = objOrigin就是浅拷贝,那么为什么修改了objAfterobjOrigin也会变化?并且修改的还是对象当中的基本数据类型!(因为后面深拷贝还设计到对象当中的数据类型)

真正的浅拷贝
  • 比如我们试图通过studen1实例,拷贝得到student2,如果是浅拷贝这种方式,大致模型可以示意成如下所示的样子:

  • 很明显,值类型的字段会复制一份,而引用类型的字段拷贝的仅仅是引用地址,而该引用地址指向的实际对象空间其实只有一份。
  • 所以浅拷贝是什么,就是赋值引用数据类型当中存储的基本数据类型,而引用数据类型当中的引用数据类型(比如数组当中嵌套对象的情况),仅仅只是将地址赋值给了另外一个对象!

深拷贝

  • 深拷贝相较于上面所示的浅拷贝,除了值类型字段会复制一份,引用类型字段所指向的对象,会在内存中也创建一个副本,就像这个样子:

  • 所以深拷贝是什么,就是不管对象当中嵌套了多少层引用数据类型还是基本数据类型,都建立一个新的给自己

一些常用的深浅拷贝方法

浅拷贝

展开运算符(扩展运算符)
  • 可以看到,除了基本数据类型拷贝了,里面的引用数据类型并未进行拷贝,修改一个拷贝后的引用数据类型会影响原来的
var objOrigin = {
    name: '李白',
    sex: '男',
    other: {
        hobby: "喝酒",
        food: "吃肉"
    }
};
//扩展运算符浅拷贝
var objAfter = {
    ...objOrigin
}
//false
console.log(objAfter === objOrigin);

//true (浅拷贝的原因)
console.log(objAfter.other === objOrigin.other);

//修改
objAfter.name = "动感超人";

//修改2
objAfter.other.food = "蔬菜"

//{ name: '动感超人', sex: '男', other: { hobby: '喝酒', food: '蔬菜' } }
console.log(objAfter);

// { name: '李白', sex: '男', other: { hobby: '喝酒', food: '蔬菜' } }
console.log(objOrigin);
Object.assign
  • 可以看到,除了基本数据类型拷贝了,里面的引用数据类型并未进行拷贝,修改一个拷贝后的引用数据类型会影响原来的
var objOrigin = {
    name: '李白',
    sex: '男',
    other: {
        hobby: "喝酒",
        food: "吃肉"
    }
};
//Object.assign浅拷贝
var objAfter = {};
Object.assign(objAfter,objOrigin)
//false
console.log(objAfter === objOrigin);

//true (浅拷贝的原因)
console.log(objAfter.other === objOrigin.other);

//修改
objAfter.name = "动感超人";

//修改2
objAfter.other.food = "蔬菜"

//{ name: '动感超人', sex: '男', other: { hobby: '喝酒', food: '蔬菜' } }
console.log(objAfter);

// { name: '李白', sex: '男', other: { hobby: '喝酒', food: '蔬菜' } }
console.log(objOrigin);

深拷贝

JSON.stringify和JSON.parse
  • 可以看到,除了基本数据类型拷贝了,里面的引用数据类型也进行了拷贝,修改一个拷贝后的引用数据类型不影响原来的
var objOrigin = {
    name: '李白',
    sex: '男',
    other: {
        hobby: "喝酒",
        food: "吃肉"
    }
};
//JSON.parse和JSON.stringify 深拷贝
var objAfter = JSON.parse(JSON.stringify(objOrigin));
//false
console.log(objAfter === objOrigin);

//true (浅拷贝的原因)
console.log(objAfter.other === objOrigin.other);

//修改
objAfter.name = "动感超人";

//修改2
objAfter.other.food = "蔬菜"

//{ name: '动感超人', sex: '男', other: { hobby: '喝酒', food: '蔬菜' } }
console.log(objAfter);

// { name: '李白', sex: '男', other: { hobby: '喝酒', food: '吃肉' } }
console.log(objOrigin);
lodash库当中的cloneDeep

cloneDeep当中的API地址

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
//比较是否相同 返回 false
console.log(deep[0] === objects[0]);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未成年梦想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值