深拷贝与浅拷贝的区别?如何实现一个深拷贝?
1. 浅拷贝是什么?规则?
浅拷贝指创建新数据,这个数据拥有原始数据属性值的一份精确拷贝。如果属性是引用类型,拷贝的就是内存地址(深层次的引用类型共享内存地址)。
实现一个浅拷贝:
function shallowClone(obj) {
const newObj = {};
for (const prop in obj) {
if (obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop];
}
}
return newObj;
}
典型的浅拷贝方式:
Object.assign({},obj)Array.prototype.concat/Array.prototype.slice- 扩展运算符
{ ...obj }/[...arr]
2. 深拷贝以及方式
深拷贝开辟一个新栈,属性完全相同,但对应两个不同的地址,修改一个对象的属性不会改变另一个。
常见深拷贝方式
(1) _.cloneDeep()(lodash)
const _ = require('lodash');
const obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] };
const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f); // false
(2) $.extend()(jQuery)
const $ = require('jquery');
const obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false
(3) JSON.parse(JSON.stringify())
const obj2 = JSON.parse(JSON.stringify(obj1));
弊端:会忽略 undefined、Symbol 和函数,不能处理循环引用、Date / RegExp / Map / Set 等。
const obj = { name: 'A', name1: undefined, name3: function () {}, name4: Symbol('A') };
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // { name: 'A' }
(4) 循环递归(最完整实现)
function deepClone(obj, hash = new WeakMap()) {
// 解决循环引用导致的爆栈
if (obj === null) return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== 'object') return obj; // 函数不深拷贝
if (hash.get(obj)) return hash.get(obj);
const cloneObj = new obj.constructor();
hash.set(obj, cloneObj);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
补充:
- 现代浏览器可直接使用
structuredClone()(原生 API)实现深拷贝,支持Date、Map、Set、ArrayBuffer、循环引用,但不能克隆函数、原型链。 - 处理循环引用必须借助
WeakMap/Map记录已拷贝对象。 - 函数、Symbol 属性、原型链是否要拷贝需要根据业务决定。
来源整理自:我的有道云笔记



