浅拷贝只会被拷贝最外边的一层,即只拷贝指针而不拷贝内容。
实现浅拷贝的方式有:
1、Object.assign
var obj = {
a: 1,
b: {
c: 1
}
}
var objCopy = Object.assign({},obj);
console.log(obj === objCopy) // 输出 false
console.log(obj.b === objCopy.b) // 输出 true
objCopy.b.c = 2;
console.log(obj.b.c) // 输出2 obj的内容发生改变
2、$.extend
var obj = {
a: 1,
b: {
c: 1
}
}
var objCopy = $.extend(false,{},obj);
console.log(obj === objCopy) // 输出 false
console.log(obj.b === objCopy.b) // 输出 true
objCopy.b.c = 2;
console.log(obj.b.c) // 输出2 obj的内容发生改变
3、简单复制
function copy(src) {
if (typeof src !== 'object') {
return src;
}
var dest = {};
for(var p in src) {
if (Object.prototype.toString.call(src[p]) ==='[object RegExp]') {
var exp = new RegExp(src[p].source,src[p].flags)
dest[p] = exp;
} else {
dest[p] = src[p];
}
}
return dest;
}
深拷贝会被拷贝全部内容,拷贝对象的改变不会影响被拷贝的对象。
实现深拷贝的方式有:
1、$.extend
var obj = {
a: 1,
b: {
c: 1
}
}
var objCopy = $.extend(true,{},obj);
console.log(obj === objCopy) // 输出 false
console.log(obj.b === objCopy.b) // 输出 false
objCopy.b.c = 2;
console.log(obj.b.c) // 输出1 obj的内容未发生改变
$.extend方式实现深拷贝,并未拷贝被拷贝对象的__proto__ ,而是把__proto__ 重置成了Object.prototype。
function Obj() {
this.name = "tom";
this.age = 18;
}
Obj.prototype.say = function() {
console.log("hello");
}
var obj = new Obj();
var objCopy = $.extend(true,{},obj);
console.log(obj.__proto__ === Obj.prototype) // 输出true
console.log(objCopy.__proto__ === Obj.prototype) // 输出false
console.log(obj.__proto__ === Object.prototype) // 输出false
console.log(objCopy.__proto__ === Object.prototype) // 输出true
若遇到两个相互引用的对象会出现死循环。
var obj = {
a: 1,
b: {
c: 1
}
}
var objCopy = {}
objCopy.a = obj;
obj.d = objCopy;
var s = $.extend(true,{},obj); // Uncaught RangeError: Maximum call stack size exceeded
2、序列号与反序列化(JSON.stringify和JSON.parse)
var obj = {
a: 1,
b: {
c: 1
}
}
var objCopy = JSON.parse(JSON.stringify(obj))
console.log(obj === objCopy) // 输出 false
console.log(obj.b === objCopy.b) // 输出 false
objCopy.b.c = 2;
console.log(obj.b.c) // 输出1 obj的内容未发生改变
var dd = {}
dd.a = obj;
obj.d = dd;
JSON.stringify(obj); //Uncaught TypeError: Converting circular structure to JSON
这种方式比较简单实用,但是如何被拷贝的对象包含函数、RegExp对象等不能被转化为json格式的对象,就不适用了。与$.extend相同若遇到两个相互引用的对象会抛出异常。
3、递归拷贝
function copy(isDeep,src) {
if (typeof src !== 'object') {
return src;
}
var dest = {};
for(var p in src) {
if (Object.prototype.toString.call(src[p]) ==='[object RegExp]') {
var exp = new RegExp(src[p].source,src[p].flags)
dest[p] = exp;
} else {
if (typeof src[p] === 'object' && isDeep) {
dest[p] = copy(isDeep,src[p]);
} else {
dest[p] = src[p];
}
}
}
return dest;
}
var obj = {
a: 1,
b: {
c: 1
}
}
var objCopy =copy(true, obj)
console.log(obj === objCopy) // 输出 false
console.log(obj.b === objCopy.b) // 输出 false
objCopy.b.c = 2;
console.log(obj.b.c) // 输出1 obj的内容未发生改变
这种方式可以实现深拷贝,但是当被拷贝对象有不可枚举属性(enumerable:
false
)时,则该属性不会拷贝。若遇到两个相互引用的对象会抛出异常。
两个对象相互引用的情况,正常情况基本不会出现,所以可不考虑这种情况。