Js 浅拷贝和深拷贝

浅拷贝和深拷贝都只针对于引用数据类型,
基本数据类型拷贝的直接是变量的值。
首先举个栗子:

var m = {a: 10, b: 20}
var n = m;
n.a = 15;
m;
// {a: 15, b: 20}

通过等号赋值的方式是浅拷贝,拷贝的是对象的引用,var n = m, 是将对象m的引用赋给了a,这时 n 和 m 指向了同一块内存地址,n 修改 a 的值也就修改了同一块内存地址,当然a的值也就变了。

var m = { a: 10, b: 20 }
var n = { a: m.a, b: m.b }
n.a = 15

此时,再输出m的值为:
在这里插入图片描述
m中a的值没有变;
而对象n中a的值为15,没有改变m对象
在这里插入图片描述
浅拷贝只复制指向某个对象的引用,而不复制对象本身,新旧对象还是共享同一块内存

但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
也就是说深拷贝会为这个对象重新开辟一块内存,来存放这个对象,和之前对象没有关系,修改这个对象也不会影响之前的对象。

深拷贝和浅拷贝最根本的区别:
在于是否是真正获取了一个对象的复制实体,而不是引用,浅拷贝只复制对象的第一层属性
深拷贝在计算机中开辟了一块内存地址用于存放复制的对象,而浅拷贝仅仅是指向被拷贝的内存地址,如果原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变。深拷贝可以对对象的属性进行递归复制

深拷贝的实现方法:
1、最简单的使用JSON.stringify和JSON.parse实现深拷贝:
JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象;

function deepCopy(object) {
    return JSON.parse(JSON.stringify(object))
}

缺陷:它会抛弃对象的constructor,深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object;
而且这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,也就是说,只有可以转成JSON格式的对象才可以这样用,像null, undefined, function 这些办法转成JSON

2.对象只有一层的话可以使用Object.assign(target, source)
3.递归拷贝

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : {};            
      arguments.callee(prop, obj[i]);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}
var str = {};
var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);

4、使用Object.create()方法

直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

var obj = {a: 10, b: 'hi', c: 20};
var newObj = Object.create(obj);
newObj.__proto__.b = 'hello';
obj;
{a: 10, b: "hello", c: 20}

5、jquery实现深拷贝,jquery 提供一个$.extend可以用来做深拷贝;

var $ = require('jquery');
var obj1 = {
    a: 3,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f);
// false

6.使用函数库lodash,也有提供_.cloneDeep用来做 Deep Copy

var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false

浅拷贝的方法:
1.当然也可以通过简单的等号=赋值来实现浅拷贝,我们也可以封装一个函数来实现
2.可以通过slice()方法实现
3.Object.assign(target, source)实现
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

var obj1 = { a: {b: "hello", c: 30} };
var sourceObj = Object.assign({}, obj1); 
sourceObj.a.b = "Hi";

在这里插入图片描述
可以看到以上obj1.a.b = ‘Hi’,值改变了,所以是浅拷贝。

注意:当object只有一层的时候,是深拷贝,例如如下:

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
obj2.b = 50;
obj1;

在这里插入图片描述
注意到obj1中b的值没有变,所以是独立copy了obj1的对象本身,而不是其引用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值