美文网首页JavaScript相关文章
前端面试必问之深拷贝浅拷贝

前端面试必问之深拷贝浅拷贝

作者: 明明你也一样 | 来源:发表于2019-11-06 11:38 被阅读0次

深拷贝、浅拷贝是前端面试的高频题目,要想知道它们的区别我们需要先搞懂它们的定义。

浅拷贝:

创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝:

将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

浅拷贝很容易理解,可以深入研究一下深拷贝。

深拷贝

乞丐版

在不使用第三方库的情况下,我们想要深拷贝一个对象,用的最多的就是下面这个方法。

JSON.parse(JSON.stringify());

复制代码这种写法非常简单,而且可以应对大部分的应用场景,但是它还是有很大缺陷的,比如拷贝其他引用类型、拷贝函数、循环引用等情况。

显然,面试时你只说出这样的方法是一定不会合格的。

接下来,我们一起来手动实现一个深拷贝方法。

基础版

如果是浅拷贝的话,我们可以很容易写出下面的代码:

function clone(target) {
    let cloneTarget = {};
    for (const key in target) {
        cloneTarget[key] = target[key];
    }
    return cloneTarget;
};

创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性依次添加到新对象上,返回新对象。

如果是深拷贝的话,考虑到我们要拷贝的对象是不知道有多少层深度的,我们可以用递归来解决问题,稍微改写上面的代码:

  • 如果是原始类型,无需继续拷贝,直接返回
  • 如果是引用类型,创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性执行深拷贝后依次添加到新对象上。

很容易理解,如果有更深层次的对象可以继续递归直到属性为原始类型,这样我们就完成了一个最简单的深拷贝:

function clone(target) {
    if (typeof target === 'object') {
        let cloneTarget = {};
        for (const key in target) {
            cloneTarget[key] = clone(target[key]);
        }
        return cloneTarget;
    } else {
        return target;
    }
};

这是一个最基础版本的深拷贝,这段代码可以让你向面试官展示你可以用递归解决问题,但是显然,他还有非常多的缺陷,比如,还没有考虑数组。

考虑数组

在上面的版本中,我们的初始化结果只考虑了普通的object,下面我们只需要把初始化代码稍微一变,就可以兼容数组了:

module.exports = function clone(target) {
    if (typeof target === 'object') {
        let cloneTarget = Array.isArray(target) ? [] : {};
        for (const key in target) {
            cloneTarget[key] = clone(target[key]);
        }
        return cloneTarget;
    } else {
        return target;
    }
};

循环引用

对象存在循环引用的情况,即对象的属性间接或直接的引用了自身的情况:

解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系,当需要拷贝当前对象时,先去存储空间中找,有没有拷贝过这个对象,如果有的话直接返回,如果没有的话继续拷贝,这样就巧妙化解的循环引用的问题。

这个存储空间,需要可以存储key-value形式的数据,且key可以是一个引用类型,我们可以选择Map这种数据结构:

  • 检查map中有无克隆过的对象
  • 有 - 直接返回
  • 没有 - 将当前对象作为key,克隆对象作为value进行存储
  • 继续克隆
function clone(target, map = new Map()) {
    if (typeof target === 'object') {
        let cloneTarget = Array.isArray(target) ? [] : {};
        if (map.get(target)) {
            return map.get(target);
        }
        map.set(target, cloneTarget);
        for (const key in target) {
            cloneTarget[key] = clone(target[key], map);
        }
        return cloneTarget;
    } else {
        return target;
    }
};

相关文章

  • 2020-01-19做些js的数组练习吧

    1.前端面试必问之数组去重 前端面试必问之数组去重 2.前端面试必问之深拷贝浅拷贝 3.

  • 前端面试必问之深拷贝浅拷贝

    深拷贝、浅拷贝是前端面试的高频题目,要想知道它们的区别我们需要先搞懂它们的定义。 浅拷贝: 创建一个新对象,这个对...

  • 面试题iOS

    面试blog 1、深拷贝浅拷贝:浅拷贝就是拷贝对象的指针,而不复制引用对象本身;深拷贝就是拷贝引用对象本身;浅复制...

  • 重拾iOS-copy

    关键词: , , , , 面试题:1)什么是深拷贝什么是浅拷贝?2)对可变对象进行copy是深拷贝还是浅拷贝?3)...

  • iOS深拷贝(MutableCopy)与浅拷贝(Copy)的区别

    深拷贝和浅拷贝的概念 iOS中有深拷贝和浅拷贝的概念,那么何为深拷贝何为浅拷贝呢?浅拷贝:浅拷贝并不拷贝对象本身,...

  • Objective-C中的浅拷贝和深拷贝

    Objective-C中的浅拷贝和深拷贝IOS开发之深拷贝与浅拷贝(mutableCopy与Copy)详解iOS ...

  • 谈谈python中的深拷贝和浅拷贝

    最近面试被问到python中深拷贝和浅拷贝的知识这里进行下总结,以便今后复习python中的深拷贝和浅拷贝和jav...

  • iOS - copy 与 mutableCopy

    一说到拷贝,就不得不提浅拷贝和深拷贝。 何谓浅拷贝?何谓深拷贝? 往简单的说: 浅拷贝:拷贝地址。 深拷贝:拷贝内...

  • iOS面试题-第二页

    11.深拷贝和浅拷贝的理解. 深拷贝;拷贝的内容. 浅拷贝:拷贝的指针. 深拷贝如: NSMutableDicti...

  • js浅拷贝深拷贝

    js浅拷贝,深拷贝的简单实现 基础数据 浅拷贝 深拷贝

网友评论

    本文标题:前端面试必问之深拷贝浅拷贝

    本文链接:https://www.haomeiwen.com/subject/wvahbctx.html