JS中的深拷贝与浅拷贝

作者 Joan 发布时间 April 13, 2017

深拷贝与浅拷贝主要是针对Object和Array这样的引用类型。当我们把一个引用赋值给一个变量的时候,这个新的变量和原引用指向的内存空间是相同的,当我们通过其中一个引用修改变量时,其他的引用的结果也会发生响应变化,这样的操作就称之为浅拷贝。


如果要拷贝一个数组

var oldArr = [1,2,3];
var newArr = oldArr;            // 浅拷贝
var newArr1 = oldArr.slice(0);  // 深拷贝
var newArr2 = oldArr.concat(); // 深拷贝

数组的截取和连接操作,都是在不改变原有数组的情况下返回一个新的数组,因此实现了深拷贝。其本质因该是:新建一个空数组,然后对原数组进行遍历操作,然后一一赋值。


如果要拷贝一个简单的对象

// 将JS对象序列化为JSON后,再解析JSON成JS对象
var newObj = JSON.parse(JSON.stringify(Obj));

对于JSON安全的对象来说,这是一种很巧妙的复制方法,但是这个方法有一定的局限性。首先对于正则表达式类型函数类型等无法进行深拷贝,会直接丢失相应的值。还有一点不好的地方是它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。

function anotherFunction() {/*..*/}

var anotherObject = {
	c: true
};

var anotherArray = [];

var myObject = {
	a: 2,
	b: anotherObject,	// 引用,不是副本
	c: anotherArray,	// 另一个引用
	d: anotherFunction
};

// 使用ES6定义的 Object.assign(..) 方法来实现浅复制
var newObj = Object.assign( {}, myObject );
newObj.a; // 2
newObj.b === anotherObject;		// true
newObj.c === anotherArray;		// true
newObj.d === anotherFunction;	// true

ES6定义的 Object.assign(..) 方法来实现浅复制。该方法的第一个参数是目标对象,之后还跟着一个或者多个源对象。它会遍历源对象的所有自身的可枚举(enumerable)的属性,并把它们复制(使用=操作符赋值)到目标对象,最后返回目标对象。


如果要深拷贝一个包含对象类型的对象

var deepCopy= function(obj) { 
    var result={};
    for (var key in obj) {
        result[key] = typeof obj[key]==='object'?deepCoyp(obj[key]): obj[key];
     } 
   return result; 
}

上述函数对于对象的每一个属性进行遍历并赋给新的对象,如果对象的某一属性是 Object 类型,那么通过递归完成深拷贝。


如果使用 Jquery

jQuery.extend( [deep ], target, object1 [, objectN ] ) 参数描述

  • [deep] 可选/Boolean类型指示是否深度合并对象,默认为false。如果该值为true,且多个对象的某个同名属性也都是对象,则该”属性对象”的属性也将进行合并。
  • [target] Object类型目标对象,其他对象的成员属性将被复制到该对象上。
  • [object1] 可选/Object类型第一个被合并的对象。
  • [objectN] 可选/Object类型第N个被合并的对象。

extend 函数:合并多个对象到 target 对象,注意 target 对象会改变。

var Chinese = {
  nation:'中国'
};
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}
var Doctor = object(Chinese); // Doctor对象继承了Chinese对象
Doctor.career = '医生';        //此时Doctor为 F {career: "医生"}
var Doctor2 = $.extend({},Doctor); // 深拷贝之后 Doctor2 为 Object {career: "医生", nation: "中国"}

Jquery中的$.extend()函数本质其实就是通过递归完成的深拷贝,它会将要拷贝的对象中的所有属性都拷贝过来,包括继承对象的属性。