JS 深拷贝与浅拷贝

64 阅读3分钟

一、数据类型 分为 基本数据类型string Number Boolean Null Undefined Symbol 和对象类型

  1. 基本数据类型都是在桟中存储的数据
  2. 引用数据类型在栈中存着在堆中的引用地址,真实的数据在堆内存中

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从对堆中获取实体

image.png

二、浅拷贝与深拷贝

深拷贝与浅拷贝都是针对Object和Array这样的引用数据类型

大致如下图

image.png

浅拷贝只复制指向某个对象的指针,而不是复制对象本身,新旧对象还是共享同一个内存。但深拷贝会另外创造一个一模一样的对象,新对象与原对象不共享内存,修改新对象不会改到原对象。 三、赋值和浅拷贝的区别

赋值:当我们把一个对象赋值给一个新的变量时,赋的其实是该对象在栈中的地址,而不是堆中的数据。也就是说两个对象指向的是同一个存储空间,无论哪个对象发生了改变,都睡改变的存储空间的内容,因此两个对象是联动的。

浅拷贝:是按位拷贝对像,会创建一个新对象,这个对象有着原始对象属性值的拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用地址,拷贝的就是内存地址,因此,其中一个对象改变,就会影响到另一个对象。

浅拷贝的手写简单方法:

  //浅拷贝       

  var obj = { a1language: [1, [23]] }
  var newOjg = [];
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
        newOjg[key] = obj[key]
    }
   }

通过for循环简单的对每一项属性做一次赋值

image.png

四、浅拷贝的实现方式

1.Object.assign()

var b = { a1 }
var c = Object.assign({}, b)
c.a = 2; //a的值被改变
//注意:当object只有一层的时候,进行的是深拷贝

2.Array.prototype.concat()

var obj = [1, { asd1 }];
var a = obj.concat([23])
a[1].asd = 26
a[0] = 6
//obj的[0]仍旧是1,但是asd的值被更改为26

3.Array.prototype.slice()

arr.slice()
补充说明:Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组的元素的一个新数组。

原数组的元素会按照下述规则进行拷贝

  1. 如果该元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
  2. 对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

五、深拷贝的实现方式

  1. JSON.parse(JSON.stringfy())
var arr={a:12}
var arr1=JSON.parse(JSON.stringify(arr))
arr1.a=13;
//发现原来的arr的a属性值并没有被更改

原理:用JSON.stringify将对象转换为JSON字符串,再用JSON.parse()把字符串解析成对象,这样就产生了一个新的对象,且会对对象开辟一个新的栈,实现深拷贝。 这种方法不能处理函数,JSON.stringify()将数组或者对象转换为JSON字符串,但是不能接受函数

  1. 手写递归实现深克隆:遍历对象、数组,知道里边都是基本数据类型,然后再去赋值,实现深拷贝。
function deepClone(source) {
    let targerObj = source.construtor === Array ? [] : {}
    for (const key in source) {
        if (Object.hasOwnProperty.call(source, key)) {
            if (source[key] && typeof source[key] === "Object") {
                targerObj[key] = deepClone(source[key])
            } else {
                targerObj[key] = source[key]
            }
        }
    }
    return targerObj;
}

3.lodash _.cloneDeep库