浅谈js引用类型数据的浅拷贝和深拷贝

0

浅拷贝:你只能得到我的银行卡,但你却永远也得不到里面的钱!

js的数据存储类型

  1. 基础类型

    直接指向存储

  2. 引用类型

    指向存储地址的指针

引用类型的浅拷贝

  var n={
  a:1,
  b:2,
  c:3,
  d:"123"
}
var m=n

直接将引用类型数据赋值给其他变量,只是将n浅拷贝给了m,当n或者m中的任意属性改变,另一者也会随之改变。

引用类型的伪深拷贝

枚举法

var n={
  a:1,
  b:2,
  c:3,
  d:"123"
}
var m={}
for(var i in n){
  m[i]=n[i]
}

for in 只能遍历对象本身及原型链上可枚举的属性,所以并不能说是完全的拷贝,但是m和n的值是互不影响的。

JSON.stringify()和JSON.parse()

var m=JSON.parse(JSON.stringify(n));
  1. 使用JSON.stringify()将对象JSON化
  2. 在使用JSON.parse()将JSON格式转换为对象

这也可以实现伪深拷贝.
但这种方法也有个很大缺陷,就是会破坏原型链,并且无法拷贝属性值为function的属性,仅仅是单纯的复制。

Object.assign()

Object.assign()方法可以实现无嵌套对象的深拷贝,我来解释一下是什么意思,就是说Object.assign()仅仅对对象的最顶层属性进行了深拷贝,而潜逃的数组或对象,并没有实现深拷贝,而是浅拷贝。
来举个栗子:

var n={
  a:1,
  b:2,
  c:3,
  d:"123",
  e:{
    a:1,
    b:2,
    c:{
          a:3
      }
    }
}
var s;
// 进行伪深拷贝,
Object.assign(s,n);
s.a='test';
console.log(s)  
console.log(n)
s.e.a="ABC"
console.log(s)  
console.log(n)

可以看出,s最顶层的属性值发生改变时,不会影响n的最顶层属性值,但是嵌套对象内的属性会同时修改。

本人最常用的深拷贝

const clone = (obj) => {
  var o
  if (typeof obj === 'object') {
    if (obj === null) {
      o = null
    } else {
      if (obj instanceof Array) {
        o = []
        for (var i = 0, len = obj.length; i < len; i++) {
          o.push(clone(obj[i]))
        }
      } else {
        o = {}
        for (var j in obj) {
          o[j] = clone(obj[j])
        }
      }
    }
  } else { o = obj }
  return o
}

这套拷贝基本可以实现深拷贝,当然如果对象结构不是很复杂,没有嵌套对象的话,还是建议使用Object.assign()