资讯专栏INFORMATION COLUMN

js深拷贝和浅拷贝

MAX_zuo / 2004人阅读

摘要:深拷贝和浅拷贝深拷贝和浅拷贝的示意图大致如下浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。参考文章什么是深拷贝和浅拷贝及其实现方式

走在前端的大道上

本篇将自己读过的相关文章中,对自己有启发的章节片段总结在这(会对原文进行删改),会不断丰富提炼总结更新。

浅拷贝
var m = { a: 10, b: 20 }
var n = m;
n.a = 15;
// 这时m.a的值是多少

m.a会输出15,因为这是浅拷贝,n和m指向的是同一个堆,对象复制只是复制的对象的引用。

深拷贝

深拷贝和上面浅拷贝不同,就是彻底copy一个对象,而不是copy对象的引用,例如,还是之前的例子,我们这么写:

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

这次,我们再来输出m.a ,发现m.a的值还是10,并没有改变,m对象和n对象是虽然所有的值都是一样的,但是在堆里面,对应的不是同一个了,这个就是深拷贝。

深拷贝和浅拷贝

深拷贝和浅拷贝的示意图大致如下:

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

浅拷贝的实现方式 1、可以通过简单的赋值实现

类似上面的例子,当然,我们也可以封装一个简单的函数,如下:

 function simpleClone(initalObj) {    
      var obj = {};    
      for ( var i in initalObj) {
        obj[i] = initalObj[i];
      }    
      return obj;
    }

    var obj = {
      a: "hello",
      b:{
          a: "world",
          b: 21
        },
      c:["Bob", "Tom", "Jenny"],
      d:function() {
          alert("hello world");
        }
    }
    var cloneObj = simpleClone(obj); 
    console.log(cloneObj.b); 
    console.log(cloneObj.c);
    console.log(cloneObj.d);

    cloneObj.b.a = "changed";
    cloneObj.c = [1, 2, 3];
    cloneObj.d = function() { alert("changed"); };
    console.log(obj.b);
    console.log(obj.c);
    console.log(obj.d);
2、Object.assign()实现

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

var obj = { a: {a: "hello", b: 21} ,c: 33};

var initalObj = Object.assign({}, obj);

initalObj.a.a = "changed";

console.log(obj.a.a); //  "changed"

initalObj.c = 66;

console.log(obj.c); //  33

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

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }
深拷贝的实现方式

1、方法一还是手动复制

和上面的举例一样,手动复制可以实现深拷贝。

2、对象只有一层的话可以使用上面的:Object.assign()函数

3、转成 JSON 再转回来

var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// { body: { a: 10 } } <-- 沒被改到
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
// false

用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。

可以封装如下函数

var cloneObj = function(obj){
    var str, newobj = obj.constructor === Array ? [] : {};
    if(typeof obj !== "object"){
        return;
    } else if(window.JSON){
        str = JSON.stringify(obj), //系列化对象
        newobj = JSON.parse(str); //还原
    } else {
        for(var i in obj){
            newobj[i] = typeof obj[i] === "object" ? 
            cloneObj(obj[i]) : obj[i]; 
        }
    }
    return newobj;
};

4、递归拷贝

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    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);

5、使用Object.create()方法

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

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === "object") {
      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}

6、jquery

jquery 有提供一个$.extend可以用来做 Deep Copy。

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

7、lodash

另外一个很热门的函数库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.什么是js深拷贝和浅拷贝及其实现方式

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90798.html

相关文章

  • JS拷贝和浅拷贝的释义

    摘要:本文解释中深拷贝和浅拷贝的区别。深拷贝深拷贝指递归的复制对象的属性给新对象。有些时候一层的深拷贝被认为是浅拷贝,比如的值是一个对象,浅拷贝出来的新对象直接引用了原对象的对象,所以也会相互影响的。 本文解释javascript中深拷贝和浅拷贝的区别。 浅拷贝/Shallow Copy 浅拷贝指拷贝了引用值。 var original = {prop1 : Prop1, prop2 : p...

    zollero 评论0 收藏0
  • 浅探js拷贝和浅拷贝

    摘要:接下来就让我们更细致的探究中的深浅拷贝。总结以上对深拷贝和浅拷贝做了简单的介绍,在深拷贝的实现上也只介绍了最简单的实现形式,并未考虑复杂情况以及相应优化,想要对深拷贝有更深入的了解,需要大家花时间去深入研究,或者可以关注我后续文章的动态。 对象和数组的拷贝对我来说一直都是一个比较模糊的概念,一直有点一知半解,但是在实际工作中又偶尔会涉及到,有时候还会一不小心掉坑里,不知道大家有没有同样...

    habren 评论0 收藏0
  • 拷贝和浅拷贝的区别

    摘要:深拷贝和浅拷贝的区别背景最近在用框架写页面,赋值给中的对象时会出现一个问题,赋值和被赋值对象之中任何一个有变化,另一个也会随之变化。 深拷贝和浅拷贝的区别 背景:最近在用vue框架写页面,赋值给Vue.$data中的对象时会出现一个问题,赋值和被赋值对象之中任何一个有变化,另一个也会随之变化。例如: var b = { foo: 123 }; var vm = new Vue(...

    suemi 评论0 收藏0
  • 重新梳理下js中的拷贝和浅拷贝

    摘要:参考链接浅拷贝最简单的浅拷贝就赋值。所谓的浅拷贝就是,后面的对象和前面的对象在第一层数据结构中指向同一个堆地址。但是如果前面的数据不止有一层,如此时,使用和方式实现的都是浅拷贝。深拷贝管你怎么变,互不影响。 参考链接:http://www.cnblogs.com/st-les...https://blog.csdn.net/hj7jay/... 浅拷贝: 1.最简单的浅拷贝就赋值。由于...

    kun_jian 评论0 收藏0
  • 拷贝和浅拷贝

    摘要:只有对于复杂数据类型才有深浅拷贝一说粗浅的解释浅拷贝并不是真的拷贝,新对象仍指向原被拷贝对象的内存地址,如有更新会被同步引用数据类型的名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值深拷贝是完全拷贝出了独立的 只有对于Object(复杂数据类型)才有深浅拷贝一说 1、粗浅的解释: 浅拷贝并不是真的拷贝,新对象仍指向原被拷贝对象的内存地址,如有更新会被同步...

    Kross 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<