web前端面试-- js深拷贝的一些bug,特殊对象属性(RegExp,Date,Error,Symbol,Function)处理,循环引用weekmap处理

本人是一个web前端开发工程师,主要是vue框架,整理了一些面试题,今后也会一直更新,有好题目的同学欢迎评论区分享 ;-)

web面试题专栏:点击此处


文章目录

深拷贝和浅拷贝的区别

在JavaScript中,深拷贝和浅拷贝是两种不同的对象复制方式。

浅拷贝是指将一个对象的引用复制给另一个对象,这意味着两个对象将共享相同的内存地址。当修改其中一个对象时,另一个对象也会受到影响。

深拷贝是指创建一个新的对象,并将原始对象的所有属性逐个复制到新对象中。这意味着两个对象是完全独立的,修改其中一个对象不会影响另一个对象。

浅拷贝示例

js 复制代码
let obj1 = { name: "Alice", age: 25 };
let obj2 = obj1; // 浅拷贝

obj2.name = "Bob";

console.log(obj1.name); // 输出: Bob,因为obj1和obj2共享相同的引用

深拷贝示例

js 复制代码
let obj1 = { name: "Alice", age: 25 };
let obj2 = JSON.parse(JSON.stringify(obj1)); // 深拷贝

obj2.name = "Bob";

console.log(obj1.name); // 输出: Alice,因为obj1和obj2是完全独立的对象

在上面的深拷贝示例中,我们使用 JSON.stringify() 将原始对象转换为字符串,然后使用 JSON.parse() 将字符串转换回对象。这样做可以创建一个新的对象,并将原始对象的属性逐个复制到新对象中,从而实现深拷贝。

需要注意的是,深拷贝有时可能会有性能和内存消耗的问题,尤其是对于包含循环引用或大量嵌套对象的复杂对象。因此,在选择深拷贝或浅拷贝时,需要根据具体情况进行权衡。


特殊对象属性

  • RegExp:不能拷贝
  • Date:时间对象会转换成字符串
  • Error:错误对象会转换成{}
  • Symbol:不能拷贝
  • Function:不能拷贝

测试对象如下:

js 复制代码
var obj = {
  name: "penk",
  age: 30,
  boo: true,
  n: null,
  un: undefined,
  sy: Symbol("penk value"),
  // big: 10n, // 浏览器没这个,nodejs可以
  child: {
    name: "penk son",
  },
  arr: [1, 2, 3, 4],
  reg: /^\d+$/,
  fn: function () {
    console.log(this.name);
  },
  time: new Date(),
  err: new Error("蛋疼"),
};
JSON.parse(JSON.stringify(obj));

obj对象

JSON转换对象

虽说是深拷贝,但是有些属性不行。

obj与JSON转换对象对比

手写深拷贝

封装好deepCopy

  1. 处理了特殊对象属性的拷贝
  2. 对于循环引用,进行了(WeekMap)去重处理。
js 复制代码
// 深拷贝函数
// 避免对象中存在重复应用的优化方案
// 通过set集合的方式,obj不同才会进行操作
function deepCopy(obj, treated = new WeakMap()) {
  // null 也是一个对象...
  // 不是对象就返回,数组也是对象~
  if (obj == null || typeof obj !== "object") return obj;
  
  // 对象的类型
  // console.log =>  '[object Object]'  '[object Array]'
  let string = Object.prototype.toString.call(obj);
  
  // 对象的构造函数
  let ctor = obj.constructor;
  // 如果有这个obj这个键名,则直接返回键值
  if (treated.has(obj)) return treated.get(obj);

  let newObj = {};

  // 是个复合数据类型,放的是地址
  treated.set(obj, newObj);

  if (string.includes("Object")) {
    // for of 不能遍历普通对象,只能遍历iterator 对象
    for (let i in obj) {
      newObj[i] = deepCopy(obj[i], treated);
    }

    return newObj;
  } else if (string.includes("Array")) {
    // 是数组
    for (let i = 0; i < obj.length; i++) {
      newObj[i] = deepCopy(obj[i], treated);
    }
  } else if (string.includes("RegExp")) {
    // 是正则对象
    newObj = new ctor(obj);
  } else if (string.includes("Date")) {
    // 是日期对象
    newObj = new ctor(obj);
  } else if (string.includes("Error")) {
    // 是Error对象
    newObj = new ctor(obj.message);
  } else if (string.includes("Symbol")) {
    // 是Symbol对象
    newObj = new ctor(obj.description);
  } else if (string.includes("Function")) {
    // 是方法
    newObj = function (...arg) {
      target.call(this, ...arg);
    };
  }

  return newObj;
}

打印如下:

obj与deepCopy转换对象对比