javaScript经典系列之浅拷贝与深拷贝
Opened this issue · 0 comments
wangzhenggui commented
前言
关于深拷贝和浅拷贝的问题一直都是面试题中比较容易问的问题,这一节,我们就来深入的了解下它!
浅拷贝
创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
使用场景
1、使用Object.assign({},object)来clone一个对象
let obj = {
a: 'a',
b: {
c: 'c'
}
}
let cloneObj = Object.assign({},obj)
console.log(obj) // "{"a":"a","b":{"c":"c"}}"
console.log(cloneObj ) // "{"a":"a","b":{"c":"c"}}"
// 修改obj对象的值类型,我们发现俩个对象互不影响
obj.a = 'a1';
console.log(obj) // "{"a":"a1","b":{"c":"c"}}"
console.log(cloneObj ) // "{"a":"a","b":{"c":"c"}}"
// 修改obj对象的引用类型值, 俩个对象的值都会变化
obj.b.c = 'c1';
console.log(obj) // "{"a":"a1","b":{"c":"c1"}}"
console.log(cloneObj ) // "{"a":"a","b":{"c":"c1"}}"
2、拷贝数组类型的时候,可以使用concat(),或者slice()函数
3、ES6中的扩展运算符可以实现浅拷贝
let obj = {
a: 'a',
b: {
c: 'c'
}
}
let cloneObj = {...obj}
console.log(obj) // "{"a":"a","b":{"c":"c"}}"
console.log(cloneObj ) // "{"a":"a","b":{"c":"c"}}"
// 修改obj对象的值类型,我们发现俩个对象互不影响
obj.a = 'a1';
console.log(obj) // "{"a":"a1","b":{"c":"c"}}"
console.log(cloneObj ) // "{"a":"a","b":{"c":"c"}}"
// 修改obj对象的引用类型值, 俩个对象的值都会变化
obj.b.c = 'c1';
console.log(obj) // "{"a":"a1","b":{"c":"c1"}}"
console.log(cloneObj ) // "{"a":"a","b":{"c":"c1"}}"
深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。
使用场景
1、JSON.parse(JSON.stringify(obj)),通过JSON的API将对象序列化之后在转化为对象实现复制一个对象,但是这个方法会存在几个问题
- 会忽略 undefined
- 会忽略 symbol
- 不能序列化函数
- 不能解决循环引用的对象
- 不能正确处理new Date()
- 不能处理正则
2、自己实现深拷贝
function cloneDeep(source) {
// 是否是对象类型
if (typeof source !== 'object') {
return source
}
let target = Array.isArray(source) ? [] : {} //判断是数组还是对象
for (let key in source) {
if (source.hasOwnProperty(key)) { // 过滤原型上的属性
target[key] = typeof source[key] === 'object' ? cloneDeep(source[key]) : source[key] // 如果属性值是对象,递归调用
}
}
return target
}
var obj = {
name: 'muyiy',
book: { title: 'You Don\'t Know JS', price: '45' },
a1: undefined,
a2: {},
a3: 123
}
var cloneObj = cloneDeep(obj);