一,浅拷贝
需要明确的一点是:只有引用数据类型才讨论深浅拷贝,基本数据类型本身存的是值,拷贝会直接开辟新的空间来存值,不存在相互影响。
拷贝的是对象的属性,一个改变,相互影响
var obj1={
name:'zhangsan',
arr:[1,2,3,4]
}
function copy(val){
var obj2={
}
for (var stl in val){
obj2[stl]=val[stl] //将val对象中的属性,一一赋值给obj2
//因为对象的第二个属性是数组(非基本数据类型,拷贝的是地址!)
}
return obj2
}
var obj2=copy(obj1)
obj1.name="libai" //它是基本数据类型,不存在深浅拷贝问题,都是深拷贝,拷贝的是值,不会互相影响
obj1.arr[0]="修改" //修改了其中一个,互相影响,都改变了,这就是浅拷贝
console.log(obj1)
console.log(obj2)
二,深拷贝
拷贝源对象,一个改变,互相不影响。
对于深拷贝而言,实际上需要讨论的是几层深拷贝。
1,对于对象的一层拷贝 ,有一个方法:
Object.assign(target, …sources) target: 目标对象,sources: 源对象
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
于是对象的一层深拷贝写法:
var obj1={
name:"beijing",
arr:[1,2,3,4]
}
var obj2=Object.assign({
},obj1) //将obj1中的可枚举属性复制一份,放到obj2中
obj1.name="shanghai"
obj1.arr[0]="更改"
console.log(obj1)
console.log(obj2)
2,对于数组的一层拷贝
arr.slice(start,end):方法可从已有数组中返回选定的元素,返回一个新数组,包含从start到end(不包含该元素)的数组元素。如果不给参数,则是全部复制
var arr1 = [1, 2, [3, 4]], arr2 = arr1.slice();
console.log(arr1); //[1, 2, [3, 4]]
console.log(arr2); //[1, 2, [3, 4]]
arr2[2][1] = 5;
console.log(arr1); //[1, 2, [3, 5]]
console.log(arr2); //[1, 2, [3, 5]] 都改变了,所以它也只能实现一层深拷贝
3,实现深拷贝的常用方式:
JSON.parse(JSON.stringify(obj)) //先把对象转化为json,再转化返回一个新的对象
var obj1 = {
x: 1,
y: {
m: 1
}
};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 2}}
这种方法不能深拷贝含有undefined、function、symbol值的对象(会直接忽略这些东西),不过 JSON.parse(JSON.stringify(obj)) 简单粗暴,已经满足 90% 的使用场景了。
4,利用递归实现深拷贝
Object.keys(obj)
对象.keys(传入源数组或者源对象)
返回值是一个数组,里面的元素是源数组的索引或者源对象的键值。
function deepCopy(obj) {
// 创建一个新对象
let result = {
}
let keys = Object.keys(obj), //获取传入对象/数组的键/索引构成的数组
key = null,
temp = null;
for (let i = 0; i < keys.length; i++) {
key = keys[i]; //依次取得对应的键/索引
temp = obj[key]; //依次取得元素/属性
// 如果元素/属性的值又是一个对象或者数组则递归操作
if (temp && typeof temp === 'object') {
//因为typeof检测[],{}和null都会返回object,所以这里用temp&&来规避null
result[key] = deepCopy(temp);//递归操作
} else {
// 否则直接赋值给新对象
result[key] = temp;
}
}
return result;
}
var obj1 = {
x: {
m: 1
},
y: undefined,
z: function add(z1, z2) {
return z1 + z2
},
a: Symbol("foo")
};
var obj2 = deepCopy(obj1);
obj2.x.m = 2;
console.log(obj1); //{x: {m: 1}, y: undefined, z: ƒ, a: Symbol(foo)}
console.log(obj2); //{x: {m: 2}, y: undefined, z: ƒ, a: Symbol(foo)}
这种方法,可以全部深度拷贝。且适用于数组和对象。