深拷贝

作者: 达文西_Huong | 来源:发表于2020-08-07 20:13 被阅读0次

深拷贝

前言

写在前面,前几天面试的时候,被问到深拷贝有什么方式实现的时候。脑袋居然一空,只记得可以转成字符串和递归,但是具体的核心原理居然一点也想不起来了。所以为了让自己想起来,我决定重新查阅文章,并且自己编写一篇文章来加深记忆。

以下的描述为阅读了网上的文章之后结合自己的理解去描述的,如果有表达不清晰或者写得不正确的地方,还请见谅,以后我会随着自己的深入学习,继续回来修改这篇文章。

基本数据类型 和 引用数据类型

拷贝,其实就是字面意思,当我们为了复制一个变量的值到另一个变量的一种行为。不过这里会存在两种情况。

我们都知道数据类型分为,基本数据类型引用数据类型。基本数据类型指的就是 String,Boolean,null,undefined,Number

基本数据类型一般是存储在栈内存中,复制的时候是值得直接传递。例如说:

    var a = 123
    var b = a

那么这个时候,会在栈内存中新分配一个空间,然后把value复制给新得变量。
如下图:

image

下面我们再来介绍一下引用数据类型

引用数据类型,其实就是数据会存放再堆内存中的。而在栈中的变量存放的是指向堆内存的地址。

而如果你想复制一个变量,给另一个变量,其实复制的只是引用地址。

    var a = new Object()
    var b = a 

如下图是复制后的效果

image

深拷贝和浅拷贝

知道了上面的这部分基础知识之后,下面就很好理解了。所谓的浅拷贝其实就是仅仅复制的是地址。而所谓的深拷贝,其实就是不仅仅复制的是引用地址,而是复制堆内存中的对象本身。

深拷贝完之后,修改原本的对象数据的时候,新复制出来的数据是不会发生变化的。

浅拷贝很简单,就不需要再说了,下面就直接上深拷贝的实现方式

通过递归的方法去实现
    function deepClone(obj) {
        var target = {}
        for(var key in obj) {
            // 过滤掉原型链上的可遍历的数据(即只复制自身的属性)
            if(Object.peototype.hasOwnProperty.call(obj, key)){
                if(typeof obj[key] === 'object'){
                    target[key] = deepClone(obj[key])
                } else {
                    target[key] = obj[key]
                }
            }
        }
        return target
    }
通过字符串的方式去实现
    function(obj) {
        // 其实就是把对象转成字符串(即把引用数据类型转成基本数据类型)
        let strObj = JSON.stringify(obj)
        let copyObj = JSON.parse(strObj)
        return copyObj
    }
通过Objcet.create() 实现
    function deepCopy(obj) {
        // 创建一个对象,并且给这个对象绑定一个原型
        // getPrototypeOf 获取原型
        var copy = Object.create(Object.getPrototypeOf(obj))
        // 遍历获取自身的属性(包含不可遍历)----并且不会从原型链上遍历
        var propNames = Objcet.getOwnPropertyNames(obj)

        propNames.forEach(function(name) {
            // 获取每一个属性的 描述 (即是否可遍历,能够执行delet,能否修改值)
            var desc = Object.getOwnPropertyDescriptor(obj, name)
            // 给一个目标对象添加一个属性,以及属性描述
            Object.defineProperty(copy, name, desc) 
        })

        return copy
    }
补充一个递归的方法
  function deepClone( obj, hash = new WeakMap() ){
    // 如果是 null 或者 undefined 我就不进行拷贝操作了
    if(obj === null ) return obj

    if(obj instanceof Date ) return new Date( obj )

    if(obj instanceof RegExp) return new RegExp(obj)

    // obj 可能是对象或者普通值,如果只是个函数的话,也不进行拷贝
    if(typeof obj !== "object") return obj

    // 是对象的话就要进行拷贝了
    if(hash.get(obj)) return hash.get(obj)

    // 找到的是所属类原型上的 constructor,而原型上的 construction 指向的是当前类的本身
    let cloneObj = new obj.constructor()

    hash.set(obj, cloneObj);

    for(let key in obj) {
        if(obj.hasOwnProperty(key)) {
            // 实现一个递归拷贝
            cloneObj[key] = deepClone(obj[key], hash)
        }
    }
    return cloneObj
    
  }

  // test

  let obj = {
      name:1,
      address:{
          x:100
      }
  }

  obj.o = obj   // 对象存在循环引用的情况
  let d = deepClone(obj)
  obj.address.x = 200
  console.log(d)```

总结

文章到这里就结束了,其实深拷贝的难点就在于一开始我们提到的。由于栈内存中存储的变量的值存储的是引用地址,而你想复制,只能通过把堆内存中的值遍历出来,然后重新添加,并且重新分配出新的堆内存和新的引用地址。


以上

参考文章: https://segmentfault.com/a/1190000018371840

相关文章

  • 对象深拷贝和浅拷贝

    浅拷贝 深拷贝 深拷贝的递归方法 深拷贝的JSON方法

  • iOS面试题-第二页

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

  • iOS基础知识点(网络摘抄)

    1.父类实现深拷贝时,子类如何实现深拷贝。父类没有实现深拷贝时,子类如何实现深拷贝? 深拷贝同浅拷贝的区别:...

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

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

  • iOS - copy 与 mutableCopy

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

  • 2018-10-10函数基础

    深拷贝和浅拷贝 深拷贝 copy.deepcopy(对象)浅拷贝 copy.copy(对象)深拷贝: 将对象对应的...

  • js浅拷贝深拷贝

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

  • iOS - Copy 与 MutableCopy

    参考链接 一、深拷贝和浅拷贝#### 深拷贝:对象拷贝 - 直接拷贝内容。 单层深拷贝:这种方式只能够提供一层内存...

  • JS中的深拷贝与浅拷贝

    知乎:js中的深拷贝和浅拷贝? 掘金: js 深拷贝 vs 浅拷贝 前言 首先深拷贝与浅拷贝只针对 Object,...

  • 深拷贝、浅拷贝的理解与使用场景

    什么是深拷贝、浅拷贝? 通俗解释:深拷贝是内容拷贝,浅拷贝是地址拷贝 区别点: 深拷贝会创建一个新的内存空间,拷贝...

网友评论

      本文标题:深拷贝

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