资讯专栏INFORMATION COLUMN

JavaScript中的浅拷贝和深拷贝

ernest.wang / 1828人阅读

摘要:在中可以通过添加一个参数来实现递归,调用就可以实现一个深拷贝。利用序列化实现一个深拷贝

在JavaScript中,对于ObjectArray这类引用类型值,当从一个变量向另一个变量复制引用类型值时,这个值的副本其实是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受到影响。

这种拷贝分为两种情况:拷贝引用和拷贝实例,也就是我们说的浅拷贝和深拷贝

浅拷贝(shallow copy)

拷贝原对象的引用,这是最简单的浅拷贝。

// 对象
var o1 = {a: 1};
var o2 = o1;

console.log(o1 === o2);  // =>true
o2.a = 2; 
console.log(o1.a); // => 2

// 数组
var o1 = [1,2,3];
var o2 = o1;

console.log(o1 === o2); // => true
o2.push(4);
console.log(o1); // => [1,2,3,4]

拷贝原对象的实例,但是对其内部的引用类型值,拷贝的是其引用,常用的就是如jquey中的$.extend({}, obj); Array.prototype.slice()Array.prototype.concat()都会返回一个数组或者对象的浅拷贝,举个例子:

var o1 = ["darko", {age: 22}];
var o2 = o1.slice(); // 根据Array.prototype.slice()的特性,这里会返回一个o1的浅拷贝对象

console.log(o1 === o2); // => false,说明o2拷贝的是o1的一个实例

o2[0] = "lee";
console.log(o1[0]); // => "darko" o1和o2内部包含的基本类型值,复制的是其实例,不会相互影响

o2[1].age = 23;
console.log(o1[1].age); // =>23 o1和o2内部包含的引用类型值,复制的是其引用,会相互影响

可以通过Array.prototype.slice()jQuery中的$.extend({}, obj)完成对一个数组或者对象的浅拷贝,我们也可以自己写一个简单浅拷贝函数来加深对浅拷贝的理解、

// 浅拷贝实现,仅供参考
function shallowClone(source) {
    if (!source || typeof source !== "object") {
        throw new Error("error arguments");
    }
    var targetObj = source.constructor === Array ? [] : {};
    for (var keys in source) {
        if (source.hasOwnProperty(keys)) {
            targetObj[keys] = source[keys];
        }
    }
    return targetObj;
}
深拷贝(deep copy)

深拷贝也就是拷贝出一个新的实例,新的实例和之前的实例互不影响,深拷贝的实现有几种方法,首先我们可以借助jQuery,lodash等第三方库完成一个深拷贝实例。在jQuery中可以通过添加一个参数来实现递归extend,调用$.extend(true, {}, ...)就可以实现一个深拷贝。

我们也可以自己实现一个深拷贝的函数,通常有两种方式,一种就是用递归的方式来做,还有一种是利用JSON.stringifyJSON.parse来做,这两种方式各有优劣,先来看看递归的方法怎么做。

jQuery中的extend方法基本的就是按照这个思路实现的,但是没有办法处理源对象内部循环引用的问题,同时对Date,Funcion等类型值也没有实现真正的深度复制,但是这些类型的值在重新定义的时候一般都是直接覆盖,所以也不会对源对象产生影响,从一定程度上来说也算是实现了一个深拷贝。

// 递归实现一个深拷贝
function deepClone(source){
   if(!source || typeof source !== "object"){
     throw new Error("error arguments", "shallowClone");
   }
   var targetObj = source.constructor === Array ? [] : {};
   for(var keys in source){
      if(source.hasOwnProperty(keys)){
         if(source[keys] && typeof source[keys] === "object"){
           targetObj[keys] = source[keys].constructor === Array ? [] : {};
           targetObj[keys] = deepClone(source[keys]);
         }else{
           targetObj[keys] = source[keys];
         }
      } 
   }
   return targetObj;
}
// test example
var o1 = {
  arr: [1, 2, 3],
  obj: {
    key: "value"
  },
  func: function(){
    return 1;
  }
};
var o3 = deepClone(o1);
console.log(o3 === o1); // => false
console.log(o3.obj === o1.obj); // => false
console.log(o2.func === o1.func); // => true
  

还有一种实现深拷贝的方式是利用JSON对象中的parsestringify,JOSN对象中的stringify可以把一个js对象序列化为一个JSON字符串,parse可以把JSON字符串反序列化为一个js对象,通过这两个方法,也可以实现对象的深复制。

我们从下面的例子就可以看到,源对象的方法在拷贝的过程中丢失了,这是因为在序列化JavaScript对象时,所有函数和原型成员会被有意忽略,这个实现可以满足一些比较简单的情况,能够处理JSON格式所能表示的所有数据类型,同时如果在对象中存在循环应用的情况也无法正确处理。

// 利用JSON序列化实现一个深拷贝
function deepClone(source){
  return JSON.parse(JSON.stringify(source));
}
var o1 = {
  arr: [1, 2, 3],
  obj: {
    key: "value"
  },
  func: function(){
    return 1;
  }
};
var o2 = deepClone(o1);
console.log(o2); // => {arr: [1,2,3], obj: {key: "value"}}

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

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

相关文章

  • 关于JavaScript的浅拷贝和深拷贝

    摘要:引用类型值引用类型值是保存在堆内存中的对象,变量保存的只是指向该内存的地址,在复制引用类型值的时候,其实只复制了指向该内存的地址。 前言 要理解 JavaScript中浅拷贝和深拷贝的区别,首先要明白JavaScript的数据类型。JavaScript有两种数据类型,基础数据类型和引用数据类型。js的基本类型:undefined,null,string,boolean,number,s...

    shenhualong 评论0 收藏0
  • JS的浅拷贝和深拷贝

    摘要:说明外层数组拷贝的是实例说明元素拷贝是引用深拷贝在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,拷贝后的对象与原来的对象完全隔离,互不影响。中的方法可以实现深拷贝,源码原理也是递归使用浅拷贝。 1.浅拷贝 当把数组或对象简单赋值给其他变量的时候,实际上进行的是浅拷贝,浅拷贝是拷贝引用,只是将拷贝后的引用指向同一个对象实例,彼此间的操作还会互相影响。 分为两种情况:直接拷贝源对象...

    xeblog 评论0 收藏0
  • JavaScript的浅拷贝和深拷贝

    摘要:但是进行的是浅拷贝,拷贝的是属性值。对象展开符深拷贝的实现方式手动复制转成再转回来只有可以转成格式的对象才可以这样用,像没办法转成沒被改到使用方法避免相互引用对象导致死循环,如的情况四参考关于的浅拷贝和深拷贝 一、理解 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。...

    GeekQiaQia 评论0 收藏0
  • 实现JS的浅拷贝和深拷贝

    摘要:浅拷贝和浅拷贝的问题,不仅在日常应用中需要注意,而且在面试和笔试中也常被用来考察应聘者,属于文体两开花的。基本数据类型引用数据类型等等基本数据类型是按值访问的,对其的拷贝会直接复制其值保存在新变量中。方法手工遍历法方法方法方法方法 浅拷贝和浅拷贝的问题,不仅在日常应用中需要注意,而且在面试和笔试中也常被用来考察应聘者,属于文体两开花的points。 什么是深拷贝和浅拷贝呢? 名称 ...

    huangjinnan 评论0 收藏0
  • js的浅拷贝和深拷贝

    摘要:拷贝分为浅拷贝和深拷贝。浅拷贝是引用复制,深拷贝是完全单纯拷贝数据的值。所以,这种方法只是简单绕过第一层箱子的引用复制深拷贝目前比较好的方法就是大法,要么就是自己写递归的深拷贝函数。附带深拷贝的自定义函数源自大佬的 经常遇到数组或对象等引用类型作为函数的参数的情况,但又不想修改原来的数据,这时候就需要拷贝(基本类型的变量不需要考虑)。拷贝分为浅拷贝和深拷贝。浅拷贝是引用复制,深拷贝是完...

    jsliang 评论0 收藏0

发表评论

0条评论

ernest.wang

|高级讲师

TA的文章

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