js 中对象的拷贝很常见,特别是在面试中很常见
一: 对象浅拷贝与深拷贝和对象引用的区别
var a= {name:'anikin'}
var b = jsons
a == b // true
b.name == 'jack'
a.name // 'jack'
上述代码中,使用了=
进行赋值,于是b
指向了a
所指向的栈的对象,也就是a
与b
指向了同一个栈对象,所以在对b.name
赋值时,a.name
也发生了变化。
为了避免上面的情况,可以对对象进行拷贝,代码如下:
var a = {name:'wanger'}
var b = Object.assign({}, a)
a===b // false
b.name = 'zhangsan'
a.name //'wanger'
上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆,这时候a与b指向的是不同的栈对象,所以对b.name重新复制也不会影响到a.name。
但是如果a.name
是一个对象的引用,而不是一个字符串,那么上面的代码也会遇到一些问题,参考如下代码:
var a = {name:{firstName:'wang',lastName:'er'}}
var b = Object.assign({}, a)
a===b // false
b.name.firstName = 'zhang'
a.name.firstName //'zhang'
b.name.firstName
又影响到了a.name.firstName
,这是因为Object.assign()
方法只是浅层拷贝,a.name
是一个栈对象的引用,赋值给b时,b.name
也同样是这个栈对象的引用,很多时候,我们不想让这种事情发生,所以我们就需要用到对象的深拷贝。
二、使用JSON.parse()与JSON.stringify()对对象进行拷贝
var b = JSON.parse(JSON.stringify(a))
这种方法只适用于纯数据json对象的深度克隆,因为有些时候,这种方法也有缺陷,参考如下代码:
var clone = function (obj) {
return JSON.parse(JSON.stringify(obj));
}
var a = {
a:function(){console.log('hello world')},
b:{c:1},
c:[1,2,3],
d:"wanger",
e:new Date(),
f:null,
g:undefined
}
var b = clone(a)
我们发现,上述的方法会忽略值为function
以及undefied
的字段,而且对date
类型的支持也不太友好。
更要紧的是,上述方法只能克隆原始对象自身的值,不能克隆它继承的值。 因此在用这个方法的时候小心使用。
三, 一般写法
function myextends(t,c){ //用后面的覆盖前面的
var t = t||{};
for( var attr in c ){
if( c.hasOwnProperty(attr) ){
if( typeof c[attr] == 'object'){
//console.log(c[attr],c[attr].Contructor )
t[attr] = (c[attr].constructor === Array)?[]:{}
arguments.callee(t[attr],c[attr])
}else{
t[attr] = c[attr]
}
}
}
return t
}