深拷贝和浅拷贝的区别
- .浅拷贝:就是拷贝一层
- 深拷贝:层层拷贝
为什么要使用深拷贝?
我们希望在改变新的数组(对象)的时候,不改变原数组(对象)
怎么检验深拷贝成功
改变任意一个新对象/数组中的属性/元素, 都不改变原对象/数组
数组的浅拷贝(只拷贝第一级数组元素)
1 .直接遍历
var array = [1, 2, 3, 4];
function copy (array) {
let newArray = []
for(let item of array) {
newArray.push(item);
}
return newArray;
}
var copyArray = copy(array);
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
2 . slice()
var array = [1, 2, 3, 4];
var copyArray = array.slice();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
slice() 方法返回一个从已有的数组中截取一部分元素片段组成的新数组(不改变原来的数组!)
用法:array.slice(start,end) start表示是起始元素的下标, end表示的是终止元素的下标
当slice()不带任何参数的时候,默认返回一个长度和原数组相同的新数组
3 . concat()
var array = [1, 2, 3, 4];
var copyArray = array.concat();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
concat() 方法用于连接两个或多个数组。( 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。)
因为我们上面调用concat的时候没有带上参数,所以var copyArray = array.concat();实际上相当于var copyArray = array.concat([]);
对象的浅拷贝
1 .直接遍历
let newobj = {},
for(let i in obj){
newobj[i]=obj[i]
}
比如 let newobj ={}; for(let i in obj){newobj[i]=obj[i]}
我们let一个newobj对象 然后for in 循环obj对象 不停的给这个obj里面追加新的属性
给新对象里面添加一个属性 值是老对象里面的值
2 .ES6的Object.assign
var obj = {
name: '张三',
job: '学生'
}
var copyObj = Object.assign({}, obj); //第一个参数是:目标对象,第二个参数是源对象
copyObj.name = '李四';
console.log(obj); // {name: "张三", job: "学生"}
console.log(copyObj); // {name: "李四", job: "学生"}
console.log(obj==copyObj); // false
Object.assign有这样一个功能他是指把源对象里面的内容和目标对象里面的内容进行融合,融合之后再把目标对象返回,相当于把obj里面的东西放到目标对象里面然后再返回给copyObj ,目标对象是一个新的空对象。
3 .ES6扩展运算符:
扩展运算符(…)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中
但是对多层嵌套对象,很遗憾,上面三种方法,都会失败:
var obj = {
name: {
firstName: '张',
lastName: '三'
},
job: '学生'
}
var copyObj = Object.assign({}, obj)
copyObj.name.lastName = '三三';
console.log(obj.name.lastName); // 三三
console.log(copyObj.name.lastName); // 三三
有没有更强大一些的解决方案呢?使得我们能够
1 .不仅拷贝第一层级,还能够拷贝数组或对象所有层级的各项值
2 . 不是单独针对数组或对象,而是能够通用于数组,对象和其他复杂的JSON形式的对象
这里我们就用到了深拷贝
深拷贝第一招 我们先用JSON.stringify转换成字符串,然后JSON.parse转换成对象
深拷贝终极大招 手写深拷贝
const obj = {
name: "zhangsan",
age: 25,
addres: {
city: "henan"
},
arr: ["a", "b", "c"]
}
const obj1 = deepCopy(obj)
obj1.addres.city = "beijing"
obj1.arr[1] = "e"
console.log(obj1);
function deepCopy(obj = {}) {
if (typeof obj == null || obj != "object") {
//如果obj为null 或者不是对象或是数组 直接返回
return obj
}
//初始化返回结果
let result
//使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”。
//这就需要用到instanceof来检测某个对象是不是另一个对象的实例。
//另外,更重的一点是 instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型。
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
//hasOwnProperty() 方法会返回一个布尔值
//指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
if (obj.hasOwnProperty(key)) {
//递归调用
result[key] = deepCopy(obj[key])
}
}
return result
}