js深度克隆
js对象组成
说对象的深度克隆之前,要先明白JS 中对象的组成。
以一句话说js中一切皆对象
具体数据类型分为两种:
- 原始数据类型
- 引用数据类型
原始数据类型:其中存储的是对象的实际地址。eg.
number、string、boolean、还有两个特殊的null、undefined
引用数据类型:其中存储的是对象的引用地址。eg.
array、function、object
克隆的概念
浅度克隆:原始类型为值传递,对象类型仍为引用传递。
深度克隆:所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中。
顾名思义,克隆就是将a同样复制一份变成b,那何为深度克隆呢?先来看一个例子:
浅克隆
var a = 1;
var b = a;
a = 10;
console.log(b); // 1
var a = 'hello';
var b = a;
a = 'world';
console.log(b); // hello
var a = true;
var b = a;
a = false;
console.log(b); // true
并且复制完成后原变量的值依旧可以重新赋值并且不影响拷贝文件
var a = 1;
var b = a;
a = 10;
console.log(b); console.log(a);// 1,10
var a = 'hello';
var b = a;
a = 'world';
console.log(b); console.log(a);// hello,world
var a = true;
var b = a;
a = false;
console.log(b); console.log(a);// true,false
对于原始数据类型来说,这种赋值式克隆已可以实现。
对于function基本也可以利用简单赋值实现克隆:
function clone(obj) {
var o = obj instanceof Array ? [] : {};
for(var k in obj)
o[k] = typeof obj[k] === Object ? clone(obj[k]) : obj[k];
return o;
}
var a = [[1, 2, 3], [4, 5, 6, 7]];
var b = clone(a);
console.log(b);
深度克隆
但是对于引用数据类型对象来说:
var a = [0, 1, 2, 3];
var b = a;
a.push(4);
console.log(b); // [0, 1, 2, 3, 4]
由于引用类型数据存储在应用地址内存中,因此赋值复制的也是这一块地址,因此相当于两个数组对象引用了一块数据地址,所以对a或者b的任何操作或者改变都会体现在对象中。
为了避免这种情况,引入了深度克隆。
function clone(obj){
var buf;
if(obj instanceof Array){
buf = [];
var i = obj.length;
while(i--){
buf[i] = clone(obj[i]);
}
return buf;
}
else if(obj instanceof Object){
buf = {};
for(var k in obj){
buf[k] = clone(obj[k]);
}
return buf;
}
else{
return obj;
}
}
或者精简的写法:
function clone(obj) {
var o = obj instanceof Array ? [] : {};
for(var k in obj)
o[k] = typeof obj[k] === Object ? clone(obj[k]) : obj[k];
return o;
}
var a = [[1, 2, 3], [4, 5, 6, 7]];
var b = clone(a);
console.log(b);
/**
* 对一个object进行深度拷贝
*
* 使用递归来实现一个深度克隆,可以复制一个目标对象,返回一个完整拷贝
* 被复制的对象类型会被限制为数字、字符串、布尔、日期、数组、Object对象。不会包含函数、正则对象等
*
* @param {Object} source 需要进行拷贝的对象
* @return {Object} 拷贝后的新对象
*/
function cloneObject (source) {
var result = source, i, len;
if (!source
|| source instanceof Number
|| source instanceof String
|| source instanceof Boolean) {
return result;
} else if (isArray(source)) {
result = [];
var resultLen = 0;
for (i = 0, len = source.length; i < len; i++) {
result[resultLen++] = cloneObject(source[i]);
}
} else if (isPlain(source)) {
result = {};
for (i in source) {
if (source.hasOwnProperty(i)) {
result[i] = cloneObject(source[i]);
}
}
}
return result;
}