js深拷贝的实现

2,005 阅读2分钟

js

今天我们来探讨下深拷贝的几种实现方式

对象的深拷贝的方法

  • Object.assign()
const obj = { a: "a" };
const clone = Object.assign({}, obj);
clone.a = "u";

console.log(obj); // { a: 'a' }
console.log(clone); // { a: 'u' }

注意:Object.assign只适用于一层对象的拷贝,如果对象层级比较多,这个方法就不适用。举个栗子:

const obj = { a: { b: "c" } };
const cloneObj = Object.assign({}, obj);

cloneObj.a.b = "u";

console.log(obj); // { a: { b: "u" } }
console.log(cloneObj); // { a: { b: "u" } }
  • JSON.stringfy()和JSON.parse()
const obj = { a: { b: "c" } };
const cloneObj = JSON.parse(JSON.stringify(obj));

cloneObj.a.b = "u";

console.log(obj); // { a: { b: "c" } }
console.log(cloneObj); // { a: { b: "u" } }
  • 转换引用地址
const obj = { a: "a" };
const cloneObj = { ...obj };

cloneObj.a = "u";

console.log(obj); // { a: "a" }
console.log(cloneObj); // { a: "u" }

注意,转换引用地址只适用于一层对象的拷贝,如果对象层级比较多,这个方法就不适用。举个栗子:

onst obj = { a: { b: "c" } };
const cloneObj = { ...obj };

cloneObj.a.b = "u";

console.log(obj); // { a: { b: "u" } }
console.log(cloneObj); // { a: { b: "u" } }
  • lodash的cloneDeep
import _ from "lodash";

const obj = { a: { b: "c" } };
const cloneObj = _.cloneDeep(obj);

cloneObj.a.b = "u";

console.log(obj); // { a: { b: "c" } }
console.log(cloneObj); // { a: { b: "u" } }

数组的深拷贝的方法

  • 转换引用地址
const arr = [1, 2, 3];
const cloneArr = [...arr];

cloneArr[0] = "u";

console.log(arr); // [1, 2, 3]
console.log(cloneArr); // ["u", 2, 3]
  • Array.prototype.slice()
const arr = [1, 2, 3];
const cloneArr = arr.slice(0);

cloneArr[0] = "u";

console.log(arr); // [1, 2, 3]
console.log(cloneArr); // ["u", 2, 3]
  • Array.prototype.concat()
const arr = [1, 2, 3];
const cloneArr = [].concat(arr);

cloneArr[0] = "u";

console.log(arr); // [1, 2, 3]
console.log(cloneArr); // ["u", 2, 3]

注意,转换引用地址、Array.prototype.slice()、Array.prototype.concat(),只适用于一层且元素都是基本类型的数组拷贝,如果数组比较复杂,这个方法就不适用。

  • JSON.stringfy()和JSON.parse()
const arr = [1, 2, 3, { a: "a" }];
const cloneArr = JSON.parse(JSON.stringify(arr));

cloneArr[3].a = "u";

console.log(arr); // [1, 2, 3, { a: "a" }]
console.log(cloneArr); // [1, 2, 3, { a: "u" }]
  • lodash的cloneDeep
import _ from "lodash";

const arr = [1, 2, 3, { a: "a" }];
const cloneArr = _.cloneDeep(arr);

cloneArr[3].a = "u";

console.log(arr); // [1, 2, 3, { a: "a" }]
console.log(cloneArr); // [1, 2, 3, { a: "u" }]

数组实现深拷贝的方法还有很多,这里就不一一展示了,有些方法有限制,注意一点就好。

下面我们来手写一个深拷贝的 cloneDeep 方法,适用于任何数组和对象的深拷贝。一起来看下它的实现

function cloneDeep(data) {
  // 判断传入的值类型
  if (!data) {
    return data;
  }
  if (typeof data !== "object") return data;
  if (data.constructor === Date) return new Date(data);
  if (data.constructor === RegExp) return new RegExp(data);
  
  // 开始克隆
  const clone = Array.isArray(data) ? [] : {};
  for (let key in data) {
    // 不克隆原型链上的属性和方法
    if (data.hasOwnProperty(key)) {
      if (typeof data[key] === "object") {
        clone[key] = cloneDeep(data[key]);
      } else {
        clone[key] = data[key];
      }
    }
  }
  return clone;
}
const arr = [1, 2, 3, { a: "b" }, [{ c: "d" }]];
const cloneArr = cloneDeep(arr);

cloneArr[3].a = "u";
cloneArr[4][0].c = "uu";

console.log(arr); // [1, 2, 3, { a: "b" }, [{ c: "d" }]]
console.log(cloneArr); // [1, 2, 3, { a: "u" }, [{ c: "uu" }]]

总结

js深拷贝就介绍到这里,感兴趣的小伙伴可以在评论区交流哦。