前端数组、对象的浅拷贝和深拷贝

322 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

主要介绍了数组和对象的浅拷贝和深拷贝,实现方式有 slice(), concat(), Array.from, 扩展运算符,Object.assign(), JSON.stringify(), 循环递归拷贝等等

浅拷贝:共用一个内存地址,只复制了指针,变化会互相影响

深拷贝:创建一个全新的对象,不共享内存,改变不会互相影响

数组

深拷贝

  • slice()
  • concat()
  • Array.from
Array.from("foo"); // 从string生成数组

const set = new Set(["foo", "bar", "baz", "foo"]);
Array.from(set); // 从 Set 生成数组

const map = new Map([
  [1, 2],
  [2, 4],
  [4, 8],
]);
Array.from(map); // 从 Map 生成数组

function f() {
  return Array.from(arguments); // 从类数组对象(arguments)生成数组
}
f(1, 2, 3);
  • 扩展运算符
// 数组拷贝
let arr = [1, 2, 3];
let arrCopy = [...arr];

// 对象拷贝
let obj = {
  a: "a",
  b: "b",
};
let objCopy = { ...obj };

// 数组合并 可代替concat
let newArr = [...arr1, ...arr2];

// 函数形参
func(1, 2, 3);
func(...rest); // 1 2 3
func(first, ...rest); // 1; 2 3

// 字符串转数组
let newArr = [...str];

对象

浅拷贝

  • Object.assign():对于简单类型和只有一层数据的对象是深拷贝,对于嵌套对象和引用类型是浅拷贝

深拷贝

  • 序列化:JSON.parse(JSON.stringify(obj))
    • 有限制,undefinedsymbol函数及其他特殊格式没法实现
  • 手写循环递归
function deepClone(obj, hash = new WeakMap()) {
  // 处理null或者undefined
  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);
  let cloneObj = new obj.constructor();
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

参考文档: