[js - 深拷贝]

191 阅读1分钟

深拷贝:

将一个引用类型赋值给另一个变量时,是将变量的指针指向那个引用类型,一旦其中某一个发生变化,另一个也会发生变化。

深拷贝的目的就是改变其中一个引用类型的值,不会改变另一个

前置知识:

原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;

引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中, 将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

const debug = true;
const log = debug ? console.log.bind(console, "*** debug ***") : () => {};

const isArray = function (o) {
  return Object.prototype.toString.call(o) === "[object Array]";
};

const isObject = function (o) {
  return Object.prototype.toString.call(o) === "[object Object]";
};

// 看这个就行了
function deepClone(obj = {}) {
  if (isObject(obj)) {
    // 如果是对象
    const r = {};
    for (let key in obj) {
      log("isObject key", key);
      if (obj.hasOwnProperty(key)) {
        r[key] = deepClone(obj[key]);
      }
    }
    return r;
  } else if (isArray(obj)) {
    // 如果是数组
    const r = [];
    const arr = obj;
    for (let i = 0; i < arr.length; i++) {
      r[i] = arr[i];
    }
    return r;
  } else {
    return obj;
  }
}

let obj1 = {
  age: 20,
  name: "lisi",
  address: {
    city: "beijing",
    area: "fengtai",
  },
  hobby: ["running", "dancing"],
};
const obj2 = deepClone(obj1);
log("obj2", obj2);

// 清晰版
const deepClone = function (value) {
  if (isObject(value)) {
    let o = {};
    const ks = Object.keys(value);
    for (let i = 0; i < ks.length; i++) {
      let k = ks[i];
      let v = value[k];
      o[k] = deepClone(v);
    }
    return o;
  } else if (isArray(value)) {
    let l = [];
    for (let i = 0; i < value.length; i++) {
      let e = deepClone(value[i]);
      l.push(e);
    }
    return l;
  } else {
    return value;
  }
};

// 简洁版:
function deepClone3(obj = {}) {
  const isObj = isObject(obj);
  const isArr = isArray(obj);
  if (isObj || isArr) {
    // 如果是对象
    const r = isObj ? {} : [];
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        r[key] = deepClone3(obj[key]);
      }
    }
    return r;
  } else {
    return obj;
  }
}

查漏补缺:

深拷贝解决循环引用的问题: juejin.cn/post/691651…

应用

cnodejs.org/topic/5231a…


let a = { b: 121, c: 232, c: { b: "1212"},}

// let b = deepClone(a)

// b.b = 121212

// console.log("b", b);


// let b = a


function deepClone(obj, hash = new WeakMap()) {
    if(typeof obj !== 'object' || obj === null) {
        return obj;
    }
    if(hash.has(obj)) {
        return hash.get(hash);
    }
    let newObj = Array.isArray(obj) ? [...obj] : {...obj};
    hash.set(obj, newObj);

    Reflect.ownKeys(obj).forEach(key => {
        newObj[key] = deepClone(obj[key], hash);
    });
    return newObj;
}