浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组和新对象只是原对象的一个引用,他们指向的是内存中的同一区域,修改一个对象就是同时修改两个对象。
深拷贝: 创建一个新的对象或数组,将原对象的所有内容都拷贝过来,相当于重新开辟了一个内存空间,不共享内存,修改新对象不会影响旧对象。
赋值就是最简单的浅拷贝,对于引用类型的数据来说,赋值赋的就是对象在栈中的地址,也就是引用。
可以复制一层的浅拷贝代码如下,它会创建一个新的对象,对于基本类型的数据,拷贝的是基本类型的值,如果是引用类型的数据,拷贝的就是栈中的指向堆的地址。
const isObject = (o) => typeof o === 'object' && o !== null;
const shallowCopy = (obj) => {
if (!isObject(obj)) return obj;
const res = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const element = obj[key];
res[key] = element;
}
}
return res;
};
如果要实现深拷贝,需要递归拷贝所有层级的内容。
可能会存在循环引用的情况如下:
const obj = {
name: 'Jack',
address: {
x: 100,
y: 200
}
}
obj.a = obj
这时我们可以 创建一个Map。记录下已经拷贝过的对象,如果说已经拷贝过,那直接返回它行了。
深拷贝代码一如下:
function deepCopy(obj, cache = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj //原始值
if (obj instanceof Date) return new Date(obj) //日期值
if (obj instanceof RegExp) return new RegExp(obj) //正则
if (cache.has(obj)) return cache.get(obj) //防止循环引用情况
let copyObj = new obj.constructor() //创建一个和obj类型一样的对象
cache.set(obj, copyObj) //放入缓存中
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copyObj[key] = deepCopy(obj[key], cache)
}
}
return copyObj
}
除此方法之外还可以使用使用JSON.stringify和JSON.parse方法,代码如下:
const obj = {
name: 'Jack',
address: {
x: 100,
y: 200
}
}
let copyObj = JSON.parse(JSON.stringify(obj))
这行代码的运行过程,就是利用 JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象;序列化的作用是存储和传输。(对象本身存储的是一个地址映射,如果断电,对象将不存在,所以要将对象的内容转换成字符串的形式再保存在磁盘上)。
但以下几种情况不适合使用json进行深拷贝
1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象;
2.如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
3.如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
4.如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null。
5.JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
6.如果对象中存在循环引用的情况也无法正确实现深拷贝;

5239

被折叠的 条评论
为什么被折叠?



