前端经典面试题之对象的深浅克隆-js

关于对象的深浅克隆

  1. 首先在我们的认知中,存在这复合数据类型,和基本数据类型。基本数据类型在使用的时候是进行传值调用址,复合数据类型是进行一个传址调用。

  2. 所以我们在对象克隆的时候就会错误的将同一个地址赋值到我们需要使用的一个新的变量之上,这样我们在使用的时候。修改值得时候就会直接在地址中修改,所以就会影响到原数组,这时候我们就可能会需要用到对象得深克隆

  3. 首先我先介绍几种浅拷贝得方法来避免使用。

    • Object.assign(),这是ES6中合并对象得方法,这是把第一个参数之后得参数全部复制到第一个对象中,这样可以实现第一层的拷贝
    • 然后我们也可以利用ES6的展开运算符来实现对第一层的浅拷贝。
  4. 接着我们就介绍一下深拷贝了

    • 最常用的一种拷贝方式JSON.parse(JSON.stringify(object))

    该方法引发的问题:

    1. 会忽略undefined
      1. 会忽略到symbol
      2. 不能序列化函数
      3. 不能解决循环引用的对象
    • 我们还可以使用lodash中的cloneDeep函数来进行对象的深克隆
    • 最后我们可以使用自己的递归方法来进行深克隆。

    1.首先我们先判断传入的对象类型,然后我们根据这个类型来创建target
    2.我们在获取源对象所有的属性名,包括不可枚举的属性
    3.之后我们遍历所有的属性名
    4.我们获取每个属性的描述对象
    5.在判断该属性是否是基础数据类型,如果是,我们就直接将当前属性放入目标对象中
    6.如果不是的话,我们就根据该属性,重新创建一个引用
    7.因为DOM非常的特殊,所以我们先判断该对象是否是DOM类型,如果是的话我们直接复制当前dom
    8.如果不是DOM,我们来判断当前属性中原型的构造
    9.我们根据构造来创建一个类型
    10.之后我们判断该属性的某个描述对象是否存在,如果存在,我们就给他们添加,
    11.这些完毕,我们在把当前引用传入当前函数,进行递归操作。
    最后我们将复制的后的值,返回出去

    function cloneObj(source, target) {
        var list = ["string", "number", "null", "undefined", "boolean", "function"]
        if (target === undefined) {
            // 先判断是不是dom节点,是就可以去直接clone节点
            if (HTMLElement.prototype.isPrototypeOf(source)) {
                target = source.cloneNode(false)
            } else {
                target = new source.constructor()
            }
        }
        // 获取对象的所有属性包括,包扩不可枚举的属性
        var names = Object.getOwnPropertyNames(source)
        for (var i = 0; i < names.length; i++) {
            var desc = Object.getOwnPropertyDescriptor(source, names[i])
            if (list.includes(typeof desc.value)) {
                Object.defineProperty(target, names[i], desc);
            } else {
                var t;
                if(HTMLElement.prototype.isPrototypeOf(desc.value)) {
                    t = desc.value.cloneNode(false)
                } else {
                    switch (desc.value.constructor) {
                        case RegExp:
                            t = new RegExp(desc.value.source, desc.value.flags)
                            break;
                        case Date:
                            t = new Date(desc.value)
                            break;
                        case Symbol:
                            t = Symbol
                            break;
                        case Set:
                            t = new Set(desc.value.values())
                            break;
                        case Map:
                            t = new Map(desc.value.entries())
                            break
                        default:
                            t = new desc.value.constructor();
                            break;
                    }
                }
                var o = {}
                o.value = t;
                desc.enumerable && (o.enumerable = desc.enumerable)
                desc.writable && (o.writable = desc.writable)
                desc.configurable && (o.configurable = desc.configurable)
                desc.set && (o.set = desc.set)
                desc.get && (o.get = desc.get)
                Object.defineProperty(target, names[i], o)
                console.log(desc.value,t)
                cloneObj(desc.value, t)
            }
        }
        return target
    }
    
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • css相关 1. 万能居中 1.margin: 0 auto;水平 2.text-align: center;水平...
    chaocc阅读 4,654评论 0 2
  • 如果你自以为会对象深拷贝的话,快来看看这篇对象进阶的文章吧~~~ 1.创建对象 对象创建的三种方式var obj ...
    learninginto阅读 3,616评论 6 10
  • 2018web前端最新面试题总结 一、Html/Css基础模块 基础部分 什么是HTML?答:​ HTML并不是...
    duans_阅读 10,089评论 3 27
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 12,217评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    余生动听阅读 13,597评论 0 11

友情链接更多精彩内容