Skip to content

12. js中的深浅拷贝

参考链接

在js中,一般使用栈内存保存基础数据类型,和引用类型地址(存取速度慢,存放量大,其引用指针存于栈区,并指向引用本身),而堆内存则存储引用数据类型。

赋值

将某一数值或某一对象赋值给变量的过程

  • 基础数据类型:赋的是值,赋值后两个变量不相互影响

    js
      var a = 100
      var b = a
      a = 200
      console.log(a,b) // 200, 100
  • 引用数据类型: 赋的是地址,两个变量具有相同的引用,指向同一个对象,相互之间会影响

js
  var a = {c: 1000};
  var b = a
  a.c = 2000
  console.log(a.c, b.c) // 2000, 2000 全部是2000,a,b指向同一份数据

浅拷贝

浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

Object.assign

将多个源对象中所有可枚举的自有属性复制到目标对象,并返回修改后的目标对象

js
  let obj1 = {
    person: {
      name: 'likewei',
      age: 25
    },
    sports: 'basketball'
  }

  let obj2 = Object.assign({}, obj1)
  obj2.person.name = 'testhaha'
  obj2.sports = 'football'
  console.log(obj1) 
  /**  {
    person: {
      name: 'testhaha',
      age: 25
    },
    sports: 'basketball'
  } */

loadsh的_.clone方法

js
  var _ = require('loadsh')
  var obj1 = {
    a:1,
    b: {f: {g: 1}},
    c: [1, 2, 3]
  }
  var obj2 = _.clone(obj1)
  console.log(obj1.b.f == obj2.b.f) // true

展开运算符(...)

js
  let obj1 = {name: 'likewei', address: {x: 1, y: 2}}
  let obj2 = {...obj1}
  obj1.address.x = 200
  obj1.name= 'kobe'
  console.log('obj2', obj2) // {name: 'likewei', address: {x: 200, y: 2}}

Array.prototype.concat

js
  let arr = [1, 3, {username: 'likewei'}]
  let arr2 = arr.concat()
  arr2[2].username = 'testhaha'
  console.log(arr[2].username) // 'likewei'

Array.prototype.slice

js
  let arr = [1, 3, {
    username: ' kobe'
    }];
  let arr2 = arr.slice()
  arr2[2].username = 'likewei'
  console.log(arr) // [1, 3, {username: 'likewei'}]

深拷贝

从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。

JSON.parse(JSON.stringify())

js
  let obj1 = {name: 'likewei', address: {x: 100, y: 100}}
  let obj2 = JSON.parse(JSON.stringify(obj1))
  obj2.address.x = 100
  console.log(obj1) // {name: 'likewei', address: {x: 100, y: 100}}

loadsh的_.clonedeep方法

js
var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false

手写递归

遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。

js
  // 丐版
  function cloneDeep(obj, map = new WeakMap()) {
    if(typeof obj == 'object') {
      let target = Array.is(obj) ? [] : {}
      if(map.get(obj)) {
        return map.get(obj)
      }
      map.set(obj, target)
      for(const i in obj) {
        target[i] = cloneDeep(obj[i], map)
      }
      return target
    } else { 
      return obj
    }
  }

KESHAOYE-知识星球