一、JavaScript ------ 基于原型的面向对象语言
JavaScript 是一门面向对象的语言,JavaScript 中的所有事物都是对象:字符串、数值、数组、函数等等,此外,JavaScript 允许自定义对象。下面我们先看一个例子:
var a = {n: 1}
var b = a;
a.x = a = {n: 2};
console.log(a.x); // undefined
console.log(b.x); // {n:1, x: object}
上面的例子中,a中添加了属性x,这时在b中也增加了属性x的引用,这让人不由想到了java中的浅拷贝概念。同样是面向对象的语言,因此javascript中同样存在着深拷贝与浅拷贝的概念;不同的是java是基于类的面向对象语言,对象(object)依靠 类(class)来产生,而javascript是基于原型的面向对象语言,对象(object)则是依靠构造器(constructor)利用原型(prototype)构造出来的。
二、浅拷贝与深拷贝的区别
JS 中的浅拷贝与深拷贝,只是针对复杂数据类型(Object,Array)的复制问题。
浅拷贝与深拷贝都可以实现在已有对象上再生出一份的作用,但是对象的实例是存储在堆内存中,然后通过一个引用值去操作对象,由此拷贝的时候就存在两种情况了:拷贝引用和拷贝实例,这也是浅拷贝和深拷贝的区别。上文中出现的例子是最简单的浅拷贝,下面我们再看一个例子:
var a = [{c:1}, {d:2}, 3];
var b = a.slice();
a[0].c = 3;
console.log(b[0].c); // 输出 3,说明其元素拷贝的是引用
a[2] = 5;
console.log(b[2]); // 输出 undefined,说明外层数组拷贝的是实例
在这种情况下,变量b拷贝的是以a为原型的实例,如果其属性元素为复杂数据类型时,内层元素拷贝引用,如果其属性为简单数据类型时,内层元素拷贝的是实例。
三、深拷贝的写法
function deepClone( obj ) {
var copy;
switch( typeof obj ) {
case "undefined":
break;
case "number":
copy = obj - 0;
break;
case "string":
copy = obj + "";
break;
case "boolean":
copy = obj;
break;
case "object":
//object 分为两种情况 对象(Object)和数组(Array)
if(obj === null) {
copy = null;
} else {
if( Object.prototype.toString.call(obj).slice(8, -1) === "Array") {
copy = [];
for( var i = 0 ; i < obj.length ; i++ ) {
copy.push(clone(obj[i]));
}
} else {
copy = {};
for( var j in obj) {
copy[j] = clone(obj[j]);
}
}
}
break;
default:
copy = obj;
}
return copy;
}
此外,深拷贝还可以使用以下方法:
- JSON.stringify() 和 JSON.parse() 的搭配使用
- jQuery的 $.extend(true,{},obj)
- lodash的_.cloneDeep和_.clone(value, true)