JS: 浅拷贝vs深拷贝 | 刷题打卡

我心飞翔 分类:javascript

一、浅拷贝

1. 概念

在JavaScript中,拷贝一般是指变量的复制过程。

对于简单类型,拷贝就是直接赋值的过程;

对于复杂类型,浅拷贝是指复制对象的引用地址的过程。如果修改了源对象的某个属性,由于引用相同,所以目标对象的属性也会被改变。

2. 测试

// 测试1

function test() {
  var obj = {
    id: 1,
    name: 'Tom',
    props: {
      age: 18,
    },
    color: ['red', 'green'],
  };

  const res = copy(obj);
  obj.props.age = 20; // 修改原对象的属性值,观察目标对象是否受影响
  console.log(res.props.age === 20); // true // 表示目标对象受到影响
}

 

3. 实现

function copy(source) {
  let res = {};
  for (const key in source) {
    res[key] = source[key];
  }
  return res;
}
 

二、深拷贝

1. 概念

对于复杂类型,浅拷贝是指完全复制一个全新的对象,修改原对象的属性,不会影响目标对象。因为复制出来的2个对象引用不同,也就是指向内存的地址不同。

2. 测试

function test() {
  var obj = {
    id: 1,
    name: 'Tom',
    props: {
      age: 18,
    },
    color: ['red', 'green'],
  };

  let res = deepCopy(obj);
  obj.props.age = 20; // 修改原对象的属性值,观察目标对象是否受影响
  console.log(res.props.age === 18); // true // 表示不受影响
}
 

3. 实现

// 第一版
function deepCopy(target, source) {
  for (const key in source) {
    const item = source[key];
    if (Array.isArray(item)) {
      target[key] = [];
      deepCopy(target[key], item);
    } else if (typeof element === 'object') {
      target[key] = {};
      deepCopy(target[key], item);
    } else {
      target[key] = item;
    }
  }
} 
 

仔细观察发现第一个版本有很多冗余的代码,改造一下:

// 第二版
function deepCopy(target, source) {
  for (const key in source) {
    const item = source[key];
    if (typeof item === 'object') {
      deepCopy(Array.isArray(target[key]) ? [] : {}, item);
    } else {
      target[key] = item;
    }
  }
} 
 

三、总结

  • 如果一个已知对象,属性都是简单类型,可以通过 JSON.parse(JSON.stringify(source))来实现深拷贝

  • 但是如果原对象中有函数、日期、正则等复杂类型的属性,转换后会出现属性丢失问题

  • 产生这种问题的根本原因是 JSON不支持这些上述复杂类型,具体解释可以看这里。

// 测试 JSON方式的深拷贝

function test() {
  var obj = {
    name: 'bird',
    speak: function() {
      console.log('ji ji ji')
    }
  }

  let res = deepClone(obj);
  console.log(res.speak); // undefined // 表示方法属性丢失了
}

function deepClone(source) {
  return JSON.parse(JSON.stringify(source));
}
 

回复

我来回复
  • 暂无回复内容