美文网首页web前端面试题汇总Web前端开发让前端飞
javascript中赋值、浅拷贝、深拷贝的区别及实例详解

javascript中赋值、浅拷贝、深拷贝的区别及实例详解

作者: loushumei | 来源:发表于2020-04-11 20:49 被阅读0次

    赋值

    当把一个对象a赋值给另外一个对象b时,赋的值是对象a在栈中的地址,而不是堆中的数据。

    let a={
        name:'xiaoming',
        age:21,
        grade:{
            language:60,
            math:81,
            english:99,
            science:94
        },
    }
    let b=a
    b.name='xiaowang'
    b.grade.language=90
    console.log('a',a)
    console.log('b',b)
    
    赋值.png

    结果分析:对象b和对象a指向同一地址,无论哪个对象发生改变,另外一个对象都会联动变化.

    浅拷贝

    浅拷贝它会创建一个新对象,不会指向同一个地址,只会赋值制对象的非对象属性
    (如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址)

    ES6中有个浅拷贝的方法Object.assign(target, ...sources)。
    let a = {
        name: '小明', 
        age: 21,
        grade: {
            language: 78,
            math: 81,
            english: 99,
            science: 94
        },
    }
    let b = {}
    Object.assign(b,a)
    b.name = '小花' 
    b.grade.english = 9 
    console.log('a', a)
    console.log('b', b)
    
    浅拷贝.png

    结果分析:
    b对象改变 name的值和grade对象,a对象只有grade对象的值发生改变,name未受影响。
    因为,name是基本类型,b改变自身值,a 不会改变;而grade是一个对象,为引用类型,b拷贝的是该对象的地址,与a指向同一个地址,所以b改变grade对象的值时,a也发生变化。

    深拷贝

    深拷贝会另外拷贝一份一个一模一样的对象,但是不同的是会从堆内存中开辟一个新的区域存放新对象,新对象跟原对象不再共享内存,修改赋值后的对象b不会改到原对象a。

    实现方式

    1、JSON.parse(JSON.stringify())

    原理

    用JSON.stringify将JSON对象转成JSON字符串,
    再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

    缺点

    由于用到了JSON.stringify(),这也会导致一系列的问题,因为要严格遵守JSON序列化规则:原对象中如果含有Date对象,JSON.stringify()会将其变为字符串,之后并不会将其还原为日期对象。或是含有RegExp对象,JSON.stringify()会将其变为空对象,属性中含有NaN、Infinity和-Infinity,则序列化的结果会变成null,如果属性中有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失,因为不支持。

    2、手写递归方法

    递归方法实现深度克隆

    /**
     * 深拷贝
     * @param {Object} obj 要拷贝对象
     */
    function deepClone(obj = {}) {
        if (typeof obj !== 'object' || obj == null) {
            // 不是对象,或者是null
            return obj
        }
        //初始化返回结果
        let result
        if (obj instanceof Array) {
            result =[]
        }else{
            result = {}
        }
        for (const key in obj) {
            //保证key不是原型的属性
            if (obj.hasOwnProperty(key)) { 
                //递归调用!!
                result[key] = deepClone(obj[key])
            }
        }
        //返回结果
        return result
    }
    
    深拷贝.png

    结果分析:b对象改变 name的值和grade对象,a均未受到影响,
    以为b跟a不共享内存地址,是从堆内存中开辟一个新的区域存放的新对象。

    相关文章

      网友评论

        本文标题:javascript中赋值、浅拷贝、深拷贝的区别及实例详解

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