一、浅拷贝
浅拷贝,指的是创建新的对象,这个对象有着原始数据属性值的一份精确拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是复杂类型,拷贝的就是内存地址
下面简单实现一个浅拷贝
function shallowClone(obj) {const newObj = {};for(let prop in obj) {if(obj.hasOwnProperty(prop)){newObj[prop] = obj[prop];}}return newObj;}
在Javascript中,存在浅拷贝的现象有:
object.assignArray.prototype.slice()
object.assign
var obj = {age: 18,nature: ['smart', 'good'],names: {name1: 'fx',name2: 'xka'},love: function () {console.log('fx is a great girl')}}var newObj = Object.assign({}, obj);
slice()
let fxArr = ["One", "Two", "Three"]let fxArrs = fxArr.slice(0)fxArrs[1] = "love";console.log(fxArr) // ["One", "Two", "Three"]console.log(fxArrs) // ["One", "love", "Three"]
二、深拷贝
深拷贝开辟一个新的栈,两个对象的属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
常见的深拷贝方式有:
_.cloneDeep()JSON.stringify
手写循环递归
_.cloneDeep()
const _ = require('lodash');const obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]};const obj2 = _.cloneDeep(obj1);console.log(obj1.b.f === obj2.b.f);// false
JSON.stringify()
const obj2=JSON.parse(JSON.stringify(obj1));
但这种方式存在缺点,会忽略undefined、symbol和函数
const obj = {name: 'A',name1: undefined,name3: function() {},name4: Symbol('A')}const obj2 = JSON.parse(JSON.stringify(obj));console.log(obj2); // {name: "A"}
手写循环递归
let obj1 = {name: 'zhangsan',child: {name: 'zhangsanfeng'}};// obj1.child.father = obj1// console.log(obj1);let m = new Map() //存的数据,会影响垃圾回收机制let wm = new WeakMap()// 存的数据 是一种弱引用(不会影响垃圾回收机制)// wm.set()// wm.get()// wm.has()function deepCopy(obj) {let newObj = {};//遍历obj的属性名和属性值 都添加到newObj中,如果属性值是一个对象,做判断,再创建给新对象,把属性值对象key和value添加到 新对象中for (let key in obj) {let value = obj[key]if (typeof value == 'object') {// 如果是 创建要给新的value ,和 value 一样// 调用自己let newValue = deepCopy(value);newObj[key] = newValue;} else {// 如果属性不是对象,就直接存入新对象中newObj[key] = value;}}return newObj;}let resObj = deepCopy(obj1)console.log(resObj === obj1);console.log(resObj.child === obj1.child);
三、两者的区别
下面首先借助两张图,可以更加清晰看到浅拷贝与深拷贝的区别
从上图发现,浅拷贝和深拷贝都创建出一个新的对象,但在复制对象属性的时候,行为就不一样