理解js中的浅拷贝和深拷贝

JavaScript的变量类型
  • Number Boolean String Null undefined Object Function
基本类型
  • Number Boolean String undefined null
  • 变量是直接按值存放的,存放在栈内存中的简单数据段,可以直接访问。
引用类型
  • Object Function
  • 存放在堆内存中的对象,变量保存的是一个指针,这个指针指向另一个位置。当需要访问引用类型(如对象,数组等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

浅拷贝

  • 复制一层对象的属性,并不包括对象里面的为引用类型的数据,当改变拷贝的对象里面的引用类型时,源对象也会改变。

深拷贝

  • 重新开辟一个内存空间,需要递归拷贝对象里的引用,直到子属性都为基本类型。两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

浅拷贝和深拷贝的区别

  • 浅拷贝是拷贝一层,深层次的对象级别的就拷贝引用。
  • 深拷贝是拷贝多层,递归复制了所有层级。

浅拷贝实现

Object.assign()
  • 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
let obj1 = {
  name: '张三',
  age: 18,
  child: {
    name: '李四',
    age: 22
  }
}
let obj2 = Object.assign({}, obj1)
obj2.age = 50
obj2.child.age = 888
console.log(obj1)
console.log(obj2)
$ node index.js
{ name: '张三', age: 18, child: { name: '李四', age: 888 } }
{ name: '张三', age: 50, child: { name: '李四', age: 888 } }
自定义方法 shadowCopy()
  • 实现简单的引用复制
function shadowCopy(obj) {
 let newObj = {}
 for (let k in obj) {
   newObj[k] = obj[k]
 }
 return newObj
}
let obj1 = {
 name: '张三',
 age: 18,
 child: {
   name: '李四',
   age: 22
 }
}
let obj2 = shadowCopy(obj1)
obj2.age = 50
obj2.child.age = 888
console.log(obj1)
console.log(obj2)
$ node index.js
{ name: '张三', age: 18, child: { name: '李四', age: 888 } }
{ name: '张三', age: 50, child: { name: '李四', age: 888 } }

深拷贝实现

JSON.paerse() JSON.stringify()
  • 用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。
缺点
  • 会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。

  • 能正确处理的对象只有 Number String Boolean Array 扁平对象,即那些能够被 json 直接表示的数据结构。

  • RegExp对象是无法通过这种方式深拷贝。

  • 只有可以转成JSON格式的对象才可以这样用,function没办法转成JSON。复制后生成的对象的function属性会直接消失,这个方法只能用在单纯只有数据的对象。

let obj1 = {
  name: '张三',
  age: 18,
  child: {
    name: '李四',
    age: 22
  },
  func() {
    console.log('hello:' + this.name)
  }
}
let obj2 = JSON.parse(JSON.stringify(obj1))
obj2.age = 50
obj2.child.age = 888
console.log(obj1)
console.log(obj1.func)
console.log('------------------------')
console.log(obj2)
console.log(obj2.func)
$ node index.js
{ name: '张三',
  age: 18,
  child: { name: '李四', age: 22 },
  func: [Function: func] }
[Function: func]
------------------------
{ name: '张三', age: 50, child: { name: '李四', age: 888 } }
undefined
自定义方法 deepCopy()
function deepCopy(obj) {
  let result = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === 'object' && obj[key]!==null) {
        result[key] = deepCopy(obj[key]);   //递归复制
      } else {
        result[key] = obj[key];
      }
    }
  }
  return result;
}
let obj1 = {
  name: '张三',
  age: 18,
  child: {
    name: '李四',
    age: 22
  },
  func() {
    console.log('hello:' + this.name)
  }
}
let obj2 = deepCopy(obj1)
obj2.name = '陈二'
obj2.age = 50
obj2.child.name = 'bgbhjbj'
obj2.child.age = 888
console.log(obj1)
console.log(obj1.func)
console.log('------------------------')
console.log(obj2)
console.log(obj2.func)
$ node index.js
{ name: '张三',
  age: 18,
  child: { name: '李四', age: 22 },
  func: [Function: func] }
[Function: func]
------------------------
{ name: '陈二',
  age: 50,
  child: { name: 'bgbhjbj', age: 888 },
  func: [Function: func] }
[Function: func]

你可能感兴趣的:(理解js中的浅拷贝和深拷贝)