如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
1. 如果是基本数据类型,名字和值都会储存在栈内存中(不存在深浅拷贝,可以理解为值拷贝)
var a = 1;
b = a; // 栈内存会开辟一个新的内存空间,此时b和a都是相互独立的
b = 2;
console.log(a); // 1
2. 如果是引用数据类型,名字存在栈内存中,值存在堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值
浅拷贝:从字面上的意思理解,是指比较浅的拷贝,它与原来的变量仍然指向同一个地址,两者之间相互影响,即其中一个改变会影响另一个的改变。浅拷贝也被称为引用拷贝,引用的意思就是取了个别名,例如张三是大名,狗蛋是他的引用,即为小名,张三变了,狗蛋自然也变了,因为他们本质上就是指同一个人
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。
js中的对象数据类型:Object Array Function Map Set,在赋值过程中都是引用拷贝
let obj = {
name: '静如秋叶',
age: 3,
height: 100
}
let obj2 = obj
obj2.name = '小花'
console.log(obj) // {name: '小花‘, age: 3, height: 100}
console.log(obj2) // {name: '小花‘, age: 3, height: 100}
深拷贝:从字面上的意思理解,是指很深的拷贝,到底有多深呢?深到不仅拷贝值,而且还独立开辟了一个空间。我的理解是:拷贝的过程中,独立地开辟了一个空间,这个对象指向这个地址,与原来的对象互不干扰。深拷贝也被称为值拷贝。
Array的深拷贝
(1) 通过slice方法
slice()操作数组时,不会对原数组有影响,会产出一个新的数组。
let arr1 = [1, 42, 5, 6]
let arr2 = arr1.slice()
arr2[0] = 100
console.log(arr1) // [1, 42, 5, 6]
console.log(arr2) // [100, 42, 5, 6]
(2)使用扩展运算符实现深拷贝
let arr5 = [0, 0, 1]
let arr6 = [...arr5]
arr5[0] = 10000
console.log(arr5) // [10000, 0, 1]
console.log(arr6) // [0, 0, 1]
(3) 通过Array.from方法
Array.from()方法能从一个类似数组或可迭代对象中返回一个新的数组实例。通过Array.from()方法能获取到一个数组的深拷贝。
let arr7 = [1, 2, 3]
let arr8 = Array.from(arr7)
arr7[1] = 1000
console.log(arr7) // [1, 1000, 3]
console.log(arr8) // [1, 2, 3]
(4)通过concat方法
数组的concat()方法,能够连接两个数组,同样不会改变原来的数组。用一个空数组连接另一个数组,即可实现深拷贝
let arr3 = ['cat', 'dog', 'pig']
let arr4 = [].concat(arr3)
arr3[2] = 'big pig'
console.log(arr3) // ['cat', 'dog', 'big pig']
console.log(arr4) // ['cat', 'dog', 'pig']
Object的深拷贝
(1)通过Object.assign()方法
ES6的Object.assign() Object.assign(target, …sources)用于对象的合并,将源对象中的所有可枚举属性,复制到目标对象中,并返回合并后的目标对象。后来的源对象的属性值,将会覆盖它之前的对象的属性。
let person = {
name: 'xia',
age: 25,
height: 160
}
let otherPerson = Object.assign({}, person)
person.age = 30
console.log(person)
console.log(otherPerson)
(2)手动实现深拷贝
let obj1 = {
a: 1,
b: 2
}
let obj2 = {
a: obj1.a,
b: obj1.b
}
obj2.a = 3;
alert(obj1.a); // 1
alert(obj2.a); // 3
(3)直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}
万能转换器(对Array和Object等都适用)
万能转换器 JSON.parse(JSON.stringify(obj))深拷贝已有对象,它可以深拷贝多层级的,不用担心嵌套问题。
- JSON.stringfy() 将对象序列化成json对象
- JSON.parse() 反序列化——将json对象反序列化成js对象
let jack = {
name: 'jack'
}
console.log(jack)
console.log(JSON.stringify(jack))
let obj = {
name: '静茹秋叶'
}
console.log('obj: ', obj)
console.log('json string: ', JSON.stringify(obj))
let str = JSON.stringify(obj)
console.log('--------------')
console.log(str)
console.log('str to obj: ', JSON.parse(str))