概念: 深拷贝:将对象从内存中完整的拷贝一份出来,在堆中开辟一片新的区域存放新对象。 浅拷贝:创建一个新对象,这个对象有原始对象的一份精确拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值;如果拷贝的是内存地址,拷贝的就是它的引用。
区别:深拷贝修改新对象不会影响原对象,它们之间互不影响;浅拷贝基本数据类型之间互不影响,引用数据类型其中一个改变了内存地址,就会影响另一个对象。
浅拷贝代码实现:
1.先看基本数据类型的浅拷贝
// 数字类型 Number
a = 1
b = a
b = 2
console.log(a, b); //1,2
// 字符串 String
a = 'lmx'
b = a
b = 'oo'
console.log(a, b); //lmx oo
// 布尔值 Boolean
a=false
b=a
b=true
console.log(a,b); //false,true
// 未定义 undefined
a = undefined
b = a
b = false
console.log(a, b) //undefined false
// 空 Null
a = null
b = a
b = undefined
console.log(a, b) //null undefined
由此得知:基本数据类型之间互不影响
2.复杂数据类型的浅拷贝
// 对象{}
a={ name:'abc' }
b=a
b.name='def'
console.log(a,b); // def,def
// 数组[]
a = ['a', 'b', 'c', 'd', 'e', 'f']
b = a
b[1] = 'd'
console.log(a, b);// ['a', 'd', 'c', 'd', 'e', 'f']
// Object.assign() 实现
let arr = [1, 2, 3, 4, 5, 6]
let newArr = Object.assign([], arr)
console.log(arr); // [1, 2, 3, 4, 5, 6]
console.log(newArr); // [1, 2, 3, 4, 5, 6]
// for in
var obj = {
name: '小猫',
age: 2,
hobby: {
eat: 'fish',
play: 'mouse'
}
}
function cat(obj) {
let newCat = {}
// for in 遍历属性
for (let key in obj) {
// hasOwnProperty:判断属性是不是自己的 返回布尔值
if (obj.hasOwnProperty(key)) {
newCat[key] = obj[key]
}
}
return newCat
}
let cats = cat(obj)
console.log(cats); //{name: '小猫', age: 2, hobby: {eat: 'fish',play: 'mouse'}}
// 扩展运算符
let obj = {
name: '胖墩~',
hobby: {
eat: 'rice',
look: 'me'
}
}
let newObj = {
...obj
}
Object.assign(obj, newObj)
newObj.hobby.look = '天空'
console.log(obj);
console.log(newObj);
// 当类型为function Date RegExp时 a保持不变
// 函数 function
a = function () {
alert('aaa')
}
b = a
b = function () {
alert('bbb')
}
console.log(a.toString(), b.toString()); // function () {alert('aaa')} function (){alert('bbb')}
// 日期 Date
a = new Date('2022/10/4 00:00:00')
b = a
b = new Date('2002/12/05 00:00:00')
console.log(a, b); // Tue Oct 04 2022 00:00:00 GMT+0800 (中国标准时间) Thu Dec 05 2002 00:00:00 GMT+0800 (中国标准时间)
// 正则 RegExp
a = new RegExp('abc')
b = a
b = new RegExp('aaa')
console.log(a, b); // /abc/ /aaa/
由此得知:当这个对象的属性是引用类型时,修改其中一个对象,另一个对象也会跟着改变,这种拷贝就是浅拷贝
深拷贝代码实现:
为什么使用深拷贝?
就是希望在改变新数组/对象的时候不影响原数组/对象
1.基本数据类型的深拷贝
// 1.
var a = 3
var b = a
b = 5
console.log(a); // 3
console.log(b); // 5
// 2.
var str='细狗'
var str1=str
str1='粗狗'
console.log(str); // 细狗
console.log(str1); // 粗狗
2.复杂数据类型的深拷贝
// JSON.parse(JSON.stringify(arr)) 这个方法无法转化 function 和 undefined
var arr = ['lmx', true, 0, [1, 2], { age: 18 }]
var newArr = JSON.parse(JSON.stringify(arr))
newArr[3][0] = 100
console.log(arr); //['lmx', true, 0, [1,2], {age:18}]
console.log(newArr); //['lmx', true, 0, [100,2], {age:18}]
// Object.assign 对象中没有嵌套对象时,才可以实现深拷贝
const foo = {
name: '张三',
age: 24
}
const newFoo = Object.assign({}, foo)
foo.age = 25
console.log(foo, newFoo) // {name: '张三', age: 25} {name: '张三', age: 24}
// structuredClone
const foo = {
name: '张三',
info: {
age: 24
}
}
const newFoo = structuredClone(foo) //
foo.info.age = 25
console.log(foo, newFoo) // { name: '张三', info: { age: 25 }} { name: '张三', info: { age: 24 }}
// 扩展运算符
let a = {
x: 1,
y: 2
}
let b = {
...a
}
b.y = 3
console.log(a.y) // 2
console.log(b.y);// 3
// 递归
function deepClone(obj) {
// 数据类型为引用数据类型
if (typeof obj === 'object') {
// 初始化返回结果
let result = Array.isArray(obj)? []: {};
for (let key in obj) {
// 避免相互引用出现死循环导致爆栈
if (obj === obj[key]) {
continue
}
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key])
}
}
return result;
} else {
// 基本数据类型,直接返回
return obj
}
}