concat方法与slice方法
这两个方法实际上返回的是一个浅拷贝的结果。
concat
var arr3 = [{name:'xiaobai',age:18},10];
var arr4 = [1,2,3];
arr5 = arr3.concat(arr4);
//更改arr3 中索引值为 0 的对象的属性
arr3[0].name = '小白';
console.log(arr5);//输出结果:[{name:'小白',age:18}, 10, 1, 2, 3]
slice
var arr3 = [{name:'xiaobai',age:18},10];
arr5 = arr3.slice();
//更改arr3 中索引值为 0 的对象的属性
arr3[0].name = '小白';
console.log(arr5);//输出结果:[{name:'小白',age:18}]
从上面两个例子可以看出,当数组中存有复杂数据类型时,他们返回的是一个浅拷贝的结果。
数组/对象的深拷贝
JSON.parse(JSON.stringify())深拷贝
var obj = {
name: 'xiaobai',
age: 18
}
var copy = JSON.parse(JSON.stringify(obj));
console.log(obj);//输出结果:{name: "xiaobai", age: 18}
console.log(copy);//输出结果:{name: "xiaobai", age: 18}
console.log(obj === copy);//输出结果:false
可以看到,对于复杂类型的对象,使用JSON先序列化然后再反序列化,得到的结果虽然一致,但是变量 obj 和 copy 所指向的对象不是同一个,他们之间的比较结果是false,这种情况下两个对象之一发生的任何变化都不会影响到其他一个。此时我们就实现了复杂类型的深拷贝了!但是千万注意!JSON.Stringtify这个方法不能深拷贝函数!!这个要记得!
基于数组的深拷贝其实就是针对数组中的复杂类型的深拷贝,所以我们对整个数组使用JSON.parse(JSON.stringify())深拷贝即可。
递归深拷贝
在使用for...in 来实现深拷贝的时候需要注意一个坑,即原型链上的可枚举属性会被遍历出来,这是我们所不希望看到的,所以进入正题之前首先说一下如何避免遍历到原型链上的可枚举属性:
var obj = {
name: 'xiaohei',
age: 18
}
//在原型链上添加一个自定义的可枚举属性
obj.__proto__.eat = 'hello';
for(var key in obj){
console.log(key);
//遍历结果:name age eat
}
可以看到,原型链上的可枚举属性也被遍历出来了,为了避免出现这样的情况,我们可以使用js提供的一个方法hasOwnProperty(),该方法会判断当前属性是自身属性还是继承而来的,或者说是自身属性还是原型链上的可枚举属性,返回值使boolean,自身属性为true,原型链可枚举属性为false。
var obj = {
name: 'xiaohei',
age: 18
}
//在原型链上添加一个自定义的可枚举属性
obj.__proto__.eat = 'hello';
for(var key in obj){
if(obj.hasOwnProperty(key)){
console.log(key);
//输出结果: name age
}
}
OK,进入正题,编写一个递归方法,用来深拷贝复杂类型:
/**
2 *
3 * @param {Object} obj 传递进去进行递归的数组或者对象
4 */
5 function deepClone(obj){
if(obj === null) return null;
if(typeof obj !== 'object') return obj;
if(obj instanceof RegExp) {
return new RegExp(obj);
}
if(obj instanceof Date) {
return new Date(obj);
}
/* 这里之所以使用constructor,是为了可以使的克隆出来的对象
与被克隆的对象都是同一个类的实例对象 */
let newObj = new obj.constructor;
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
newObj[key] = deepClone(obj[key]);
}
}
return newObj;
}
24
25 var arr = [1, 2, { name: 'xiaohei', age: 18 }];
26 var newArr = deepClone(arr);
27 //修改父数组中对象元素的属性值
28 arr[2].name = '小黑';
29 console.log(arr);
30 console.log(newArr);
31 console.log(arr === newArr);