深拷贝与浅拷贝

学习深拷贝和浅拷贝时看了某站一个阿婆主的讲解,个人觉得不错哦!(【前端面试题之深拷贝与浅拷贝-哔哩哔哩】https://b23.tv/6WeEfop)

首先我们需要知道js的数据类型:

1.基本数据类型(六种)存放在栈中:Number、String、Boolean、Null、Undefined、Symbol(ES6),这些数据可以直接保存在变量中的实际值。(按值传递)

var a = 25;
var b = a;
a=11;
console.log("a=", a);
console.log("b=", b);

 

 在修改a时并不会改到b;

 

2.引用数据类型(也叫对象数据类型,同时保存在栈区和堆区中):function、object、array、date、RegExp。

var obj1 = {a:10,b:20,c:30};
var obj2 = obj1;
obj2.b = 100;
console.log(obj1);
console.log(obj2);

 

复制一份obj1叫做obj2,然后把obj2.b改成100,但却不小心改到obj1.b,因为他们根本是同一个对象,这就是所谓的浅拷贝。

正确写法:

var obj1 = {a:10,b:20,c:30};
var obj2 = {a:obj1.a,b:obj1.b,c:obj1.c};
obj2.b = 100;
console.log(obj1);
console.log(obj2);

  

 这样就是深拷贝,不会改到原本的obj1.

实现深拷贝的方法:

1.JSON.parse(JSON.stringfy())

缺点:

(1)函数无法拷贝

(2)正则无法拷贝

(3)undefined无法拷贝

优点:二层以下也可以实现深拷贝

let obj1 = {
    a:1,
    say(){
        console.log(1)
    },
    reg:/\d/,
    date:undefined,
    person:{
        name :'张三' 
    }
}
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.a = 2;
obj1.person.name = "李四";
console.log("obj2=", obj2)

2.Object.assign(obj2,obj1)

优点:

  (1)可以拷贝函数

(2)可以拷贝正则

(3)可以拷贝undefined

缺点:二层以下不能实现深拷贝(所以该方法实现的是浅拷贝)

let obj1 = {
    a:1,
    say(){
        console.log(1)
    },
    reg:/\d/,
    date:undefined,
    person:{
        name :'张三' 
    }
}
let obj2 = {};
Object.assign(obj2,obj1);
obj1.a = 2;
obj1.person.name = "李四";

   

所以我们应该怎么实现深度拷贝呢?

(下面这部分内容是转了一位大佬的博客内容:【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法 - 听风是风 - 博客园

(1)递归去复制所有层级属性

function deepClone(obj) {
  let objClone = Array.isArray(obj) ? [] : {}
  if (obj && typeof obj === 'object') {
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        // 判断obj子元素是否为对象,如果是,递归复制
        if (obj[key] && typeof obj[key] === 'object') {
          objClone[key] = deepClone(obj[key])
        } else {
          objClone[key] = obj[key]
        }
      }
    }
  }
  return objClone
}
 
let a = [1,2,3,4]
let b = deepClone(a)  // [1,2,3,4]
a[0] = 2  // [2,2,3,4]
b  //  [1,2,3,4]
那是不是说slice方法也是深拷贝了,毕竟b也没受a的影响,上面说了,深拷贝是会拷贝所有曾经的属性,还是这个例子,我们把a改改
let a = [0,1,[2,3],4]
let b = a.slice()
a[0] = 1
a[2][0] = 1  // [1,1,[1,3],4]
b  // [0,1,[1,3],4]

拷贝的不彻底啊,b对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了a的控制,说明slice根本不是真正的深拷贝。

这里引用知乎问答里面的一张图

第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。

同理,concat方法与slice也存在这样的情况,他们都不是真正的深拷贝,这里需要注意。

(2)用JSON对象的parse和stringify

function deepClone (obj) {
  let _obj = JSON.stringify(obj)
  let objClone = JSON.parse(_obj)
  return objClone
}
 
let a = [0,1,[2,3],4]
let b = deepClone(a)
a[0] = 1  
a[2][0] = 1  // [1,1,[1,3],4]
b  // [0,1,[2,3],4]

(3)JQ的extend方法

JQ里有extend方法也可以拷贝对象。

$.extend([deep ], target, object1 [, objectN ])

deep表示是否深拷贝,为true为深拷贝;为false,为浅拷贝。

target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。

object1  objectN可选。 Object类型 第一个以及第N个被合并的对象。 

let a = [0,1,[2,3],4]
let b = $.extend(true, [], a)
a[0] = 1
a[2][0] = 1  // [1,1,[1,3],4]
b  // [0,1,[2,3],4]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陛下,再来一杯娃哈哈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值