JS 深度克隆的实现方法

方法一:正统做法(扩展性高,推荐)

function test() {

  this.a = 1;

  this.b = 2;

}

test.prototype.c = 3; // 原型上的属性

const obj = new test();

console.log("原对象", obj);

console.log("克隆后的对象", deepClone(obj));

/** JS 深度克隆
 * @param value 需要克隆的值
 */
function deepClone(value) {
  // 排除原始类型的情况,函数时也满足此条件
  if (typeof value !== "object" || value === null) {
    return value;
  }
  // 克隆结果:1.数组 2.普通对象
  const result = Array.isArray(value) ? [] : {};
  // 设置克隆结果的原型链为 value 的原型链(即保持原型一致)
  Object.setPrototypeOf(result, Object.getPrototypeOf(value));
  // 浅层克隆
  for (const key in value) {
    // 排除原型上的属性
    if (value.hasOwnProperty(key)) {
      result[key] = deepClone(value[key]); // 针对这个对象的每一个属性值进行克隆,则达到深度克隆效果
    }
  }
  return result;
}

解决环形引用问题

function test() {

  this.a = 1;

  this.b = 2;

}

test.prototype.c = 3; // 原型上的属性

const obj = new test();

obj.c = obj; // 环形引用 obj.c 等于 obj 本身

console.log("原对象", obj);

console.log("克隆后的对象", deepClone(obj));

/* 建立缓存区,解决环形引用问题 */
let cache = new WeakMap(); // 使用 WeakMap 为了防止内存泄露

/** JS 深度克隆
 * @param value 需要克隆的值
 */
function deepClone(value) {
  // 排除原始类型的情况,函数时也满足此条件
  if (typeof value !== "object" || value === null) return value;
  // 解决环形引用问题(即循环引用)
  const cached = cache.get(value);
  if (cached) return cached;
  // 克隆结果:1.数组 2.普通对象
  const result = Array.isArray(value) ? [] : {};
  // 设置克隆结果的原型链为 value 的原型链(即保持原型一致)
  Object.setPrototypeOf(result, Object.getPrototypeOf(value));
  // 环形引用时将克隆的值储存到缓存中
  cache.set(value, result);
  // 浅层克隆
  for (const key in value) {
    // 排除原型上的属性
    if (value.hasOwnProperty(key)) {
      result[key] = deepClone(value[key]); // 针对这个对象的每一个属性值进行克隆,则达到深度克隆效果
    }
  }
  return result;
}

方法二:JSON 序列化与反序列化(无扩展性)

const obj = { id: 1, name: "张三", age: 18 };

const newObj = JSON.parse(JSON.stringify(obj));
newObj.name = "艾凯";
newObj.age = 22;

console.log("obj", obj);
console.log("newObj", newObj);

功能上没有问题,但这种做法有一些明显的缺陷。

如果这个对象里面含有 Map 之类的这些玩意,克隆之后这个 mapList 就不再是一个 Map 结构了。

或者是这个对象里面有一些函数之类的,克隆之后这个函数后都没有了。

const obj = { id: 1, name: "张三", age: 18, mapList: new Map(), fun: function () { } };

const newObj = JSON.parse(JSON.stringify(obj));
newObj.name = "艾凯";
newObj.age = 22;

console.log("obj", obj);
console.log("newObj", newObj);

方法三:标签页通信

异步的,比较耗时,没用过

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值