JavaScript对象深度克隆

JavaScript并没有提供对象的复制方法,只能借助第三方库或自己实现对象的深度克隆。具体方法如下:

第三方库实现

实现JavaScript库的深度克隆的第三方库主要有:

  • Underscore —— _.clone()
  • jQuery —— $.clone() / $.extend()
  • lodash —— _.clone() / _.cloneDeep()
  • 借助 JSON 全局对象

Underscore —— _.clone()

在 Underscore 中有这样一个方法:_.clone(),这个方法实际上是一种浅复制 (shallow-copy),所有嵌套的对象和数组都是直接复制引用而并没有进行深复制。其代码如下:

1
2
3
4
5
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};

jQuery —— $.clone() / $.extend()

在 jQuery 中也有这么一个叫 $.clone() 的方法,可是它并不是用于一般的 JS 对象的深复制,而是用于 DOM 对象。与 Underscore 类似,可以通过 $.extend() 方法来完成深复制。值得庆幸的是,在 jQuery 中可以通过添加一个参数来实现递归extend。调用$.extend(true, {}, …)就可以实现深复制。

1
2
3
4
5
6
7
8
9
10
11
var x = {
a: 1,
b: { f: { g: 1 } },
c: [ 1, 2, 3 ]
};

var y = $.extend({}, x), //shallow copy
z = $.extend(true, {}, x); //deep copy

y.b.f === x.b.f // true
z.b.f === x.b.f // false

lodash —— _.clone() / _.cloneDeep()

在lodash中关于复制的方法有两个,分别是.clone()和.cloneDeep()。其中.clone(obj, true)等价于.cloneDeep(obj)。

借助 JSON 全局对象

针对纯 JSON 数据对象的深复制,使用 JSON 全局对象的 parse 和 stringify 方法来实现深复制也算是一个简单讨巧的方法,但它能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。

1
2
3
4
function jsonClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
var clone = jsonClone({ a:1 });

递归实现

下面是递归实现对象深度克隆的可用方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function clone(obj) {
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;

// Handle Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}

// Handle Array
if (obj instanceof Array) {
var copy = [];
for (var i = 0, var len = obj.length; i < len; ++i) {
copy[i] = clone(obj[i]);
}
return copy;
}

// Handle Object
if (obj instanceof Object) {
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}

throw new Error("Unable to copy obj! Its type isn't supported.");
}

参考链接

  1. 深入剖析 JavaScript 的深复制,by 咀嚼之味.
  2. 深入理解JavaScript中的对象复制(Object Clone),by jingxian.
  3. JavaScript语言精粹(修订版),by Douglas Crockford著.