返回

深度理解前端手写代码面试题——深克隆方法详解

前端

前言

大家好,我是晚天。在前端面试中,手写代码是不可或缺的一部分。常见的手写代码题也基本是可枚举的。网上也有很多面经文章会讲到手写代码,但是大都不够全面、不够深度,有些低质量文章甚至会误导初学者。

本文将深度解析前端面试中的经典手写代码题——深克隆方法,帮助读者全面理解深克隆与浅克隆的区别、深克隆的实现原理及其实现方法,以及如何应对循环引用的问题,从而在面试中脱颖而出。

深克隆与浅克隆

在理解深克隆之前,我们先来了解一下浅克隆。浅克隆只复制对象的属性,而不会复制对象引用的对象。也就是说,浅克隆只复制一层,而深克隆会复制对象的所有层级,包括对象引用的对象。

举个例子,我们有一个对象obj,其中有一个属性name,还有一个属性childrenchildren是一个数组,其中包含两个对象child1child2

const obj = {
  name: 'obj',
  children: [
    { name: 'child1' },
    { name: 'child2' }
  ]
};

如果我们使用浅克隆来复制obj,那么新对象obj2将具有相同的属性和属性值,但是obj2.children将引用与obj.children相同的对象。

const obj2 = Object.assign({}, obj);

如果我们修改obj2.children[0].name,那么obj.children[0].name也会被修改,因为它们引用的是同一个对象。

obj2.children[0].name = 'child1-modified';
console.log(obj.children[0].name); // 'child1-modified'

如果我们使用深克隆来复制obj,那么新对象obj3将具有相同的属性和属性值,但是obj3.children将引用与obj.children不同的对象。

const obj3 = JSON.parse(JSON.stringify(obj));

如果我们修改obj3.children[0].name,那么obj.children[0].name不会被修改,因为它们引用的是不同的对象。

obj3.children[0].name = 'child1-modified';
console.log(obj.children[0].name); // 'child1'

深克隆的实现原理

深克隆的实现原理很简单,就是将对象的所有属性和属性值都复制一遍,包括对象引用的对象。

我们可以使用递归算法来实现深克隆。首先,我们需要创建一个新的对象newObj,然后遍历obj的所有属性,将每个属性的值复制到newObj中。

function deepClone(obj) {
  const newObj = {};
  for (const key in obj) {
    newObj[key] = obj[key];
  }
  return newObj;
}

如果obj的某个属性是一个对象,那么我们需要递归地克隆该对象。

function deepClone(obj) {
  const newObj = {};
  for (const key in obj) {
    if (typeof obj[key] === 'object') {
      newObj[key] = deepClone(obj[key]);
    } else {
      newObj[key] = obj[key];
    }
  }
  return newObj;
}

深克隆的实现方法

我们可以使用多种方法来实现深克隆,包括:

  • 使用递归算法
  • 使用JSON.parse(JSON.stringify(obj))
  • 使用lodash.cloneDeep(obj)

如何应对循环引用

在实现深克隆时,我们需要特别注意循环引用。循环引用是指对象本身或其属性引用了自身。如果我们直接使用递归算法来实现深克隆,那么遇到循环引用时就会陷入死循环。

为了应对循环引用,我们可以使用哈希表来存储已经克隆过的对象。当我们遇到一个对象时,我们首先检查哈希表中是否已经存在该对象。如果存在,那么我们直接返回哈希表中存储的克隆对象。如果不存在,那么我们克隆该对象,并将其存储在哈希表中。

function deepClone(obj, hash = new Map()) {
  const newObj = {};
  for (const key in obj) {
    if (typeof obj[key] === 'object' && obj[key] !== null) {
      if (hash.has(obj[key])) {
        newObj[key] = hash.get(obj[key]);
      } else {
        hash.set(obj[key], newObj);
        newObj[key] = deepClone(obj[key], hash);
      }
    } else {
      newObj[key] = obj[key];
    }
  }
  return newObj;
}

结语

深克隆是前端面试中常见的手写代码题之一。通过本文的讲解,希望读者能够全面理解深克隆与浅克隆的区别、深克隆的实现原理及其实现方法,以及如何应对循环引用的问题。

在实际面试中,面试官可能会要求你手写深克隆代码,并可能给你一些特殊场景,比如存在循环引用等。因此,在准备面试时,除了掌握基本原理和实现方法外,还需要多做一些练习,才能在面试中游刃有余。