深拷贝和浅拷贝
数组的浅拷贝
slice和concat方法就可以实现
var arr = ['old', 1, true, null, undefined];
var new_arr = arr.concat();
var new_arr = arr.slice();
new_arr[0] = 'new';
console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]
但是如果数组嵌套了对象或者数组的话,比如:
var arr = [{old: 'old'}, ['old']];
var new_arr = arr.concat();
arr[0].old = 'new';
arr[1][0] = 'new';
console.log(arr) // [{old: 'new'}, ['new']]
console.log(new_arr) // [{old: 'new'}, ['new']]
这是因为对象和数组都是引用类型的值。也就是用以上这两种方法,克隆的都不彻底。面对对象和数组的时候,实际上拷贝的是他们的引用。
我们把这种复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
数组的深拷贝
首先讲一个最简单的方法~!他不仅能适用于嵌套的数组还适用于嵌套的对象!
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
var new_arr = JSON.parse(JSON.stringify(arr))
console.log(arr) // ['old', 1, true, ['old1', 'old2'], {old: 1}]
就是有一个问题,不能拷贝函数,我们做个试验:
var arr = [function(){
console.log(a)
}, {
b: function(){
console.log(b)
}
}]
var new_arr = JSON.parse(JSON.stringify(arr));
console.log(new_arr); // {null,{}} 变成空的了!!
以上是一些技巧类的实现,现在我们来自己写一个浅拷贝代码
// 浅拷贝
function shallowCopy(obj){
if(typeof obj != 'object'){
return
}
var newobj = Array.isArray(obj)?[]:{}
for(var key in obj){
if(obj.hasOwnProperty(key)){
newobj[key] = obj[key]
}
}
return new obj
}
那如何实现一个深拷贝?思路就是在赋值的时候先判断一下这个值是不是一个object。如果是,那么就递归他
function deepCopy(obj){
if(typeof obj != 'object'){
return
}
var newobj = Array.isArray(obj)?[]:{}
for(var key in obj){
if(obj.hasOwnProperty(key)){
newobj[key] = typeof obj[key] == 'object'? deepCopy(obj[key]) : obj[key]
}
}
return newobj
}
来测试一下
var arr = ['old', 1, true,null,undefined,[1,2],{a:'b',c:'d'}
,function(){console.log('a')},{'shit':function(){console.log('shit')}}];
function deepCopy(obj){
if(typeof obj != 'object'){
return
}
var newobj = Array.isArray(obj)?[]:{}
for(var key in obj){
if(obj.hasOwnProperty(key)){
newobj[key] = typeof obj[key] == 'object'? deepCopy(obj[key]) : obj[key]
}
}
return newobj
}
var newarr = deepCopy(arr)
console.log(newarr)
// [ 'old',
1,
true,
{},
undefined,
[ 1, 2 ],
{ a: 'b', c: 'd' },
[Function],
{ shit: [Function: shit] } ]
发现了一个问题,就是null被转换为空对象了
最终版本:
function deepCopy(obj){
if(typeof obj != 'object'){
return
}
var newobj = Array.isArray(obj)?[]:{}
for(var key in obj){
if(obj.hasOwnProperty(key)){
if(Object.prototype.toString.call(obj[key]).slice(8,-1) == 'Null'){
newobj[key] = null
}else{
newobj[key] = typeof obj[key] == 'object'? deepCopy(obj[key]) : obj[key]
}
}
}
return newobj
}