JS 深拷贝 VS 浅拷贝

复习到深浅拷贝问题,简单Mark一下实现方法。函数

## 写在前面ui

首先咱们得清楚基本概念。拷贝(Copy)即复制。spa

浅拷贝:建立一个新对象,保存原始对象属性值精准拷贝。若是属性是基本类型,拷贝的是基本类型的值,若是属性是引用类型,拷贝的是内存地址,并不会占用新的内存,这种状况下若是其中一个对象改变了这个地址,会影响到另外一个对象。浅拷贝只复制指向某个对象的指针,而不复制对象自己。**新旧对象共享同一块内存**。prototype

深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,增长了内存,且修改新对象不会影响原对象。**新对象与原对象不共享内存**。指针

## 赋值和深/浅拷贝的区别(针对引用类型)code

赋值:把一个对象赋值给一个新的变量时,赋的实际上是该对象的在栈中的地址,而不是堆中的数据。对象

浅拷贝:从新在堆中建立内存,拷贝先后对象的基本数据类型互不影响,但拷贝先后对象的引用类型因共享同一块内存,会相互影响。blog

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

## 浅拷贝的实现方案内存

### 0x01 Object.assign()
把任意多个源对象自身的可枚举属性拷贝给目标对象,而后返回目标对象。

let obj2 = Object.assign({}, obj1)

 

### 0x02 函数库lodash的_.clone方法

var _ = require('lodash');

var obj2 = _.clone(obj1);

 

### 0x03 展开运算符
同object.assign()功能相同

let obj2 = {...obj1}

 

### 0x04 Array.prototype.concat()

let arr2 = arr1.concat()

 

### 0x05 Array.prototype.slice()

let arr2 = arr1.slice()

 

## 深拷贝的实现方案

### 0x01 JSON.parse()和JSON.stringify()

let arr2 = JSON.parse(JSON.stringify(arr1));

 

缺点是不能处理函数和正则

### 0x02 函数库lodash的_.cloneDeep方法

var _ = require('lodash');

var obj2 = _.cloneDeep(obj1);

 

### 0x03 jQuery.extend()方法

$.extend(deepCopy,target,obj1,[objN]) // 第一个参数为true就是深拷贝

 

### 0x04 手写递归实现
解决循环引用的问题

function deepClone(obj, hash=new WeakMap()) {
  if(obj == null) return obj; // 不操做
  if(obj instanceof Date) return new Date(obj);
  if(obj instanceof RegExp) return new RegExp(obj);
  // 普通值/函数不须要深拷贝
  if(typeof obj !== "object") return obj;
  // 是对象的话要进行深拷贝
  if(hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的constructor指向的是当前类自己
  hash.set(obj. cloneObj);
  for(let key in obj) {
    if(obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash)
    }
  }
  return cloneObj;
}
相关文章
相关标签/搜索