理解前端JS深浅拷贝
前置知识:
- JS的一般数据类型的存储(stirng number boolean undefinded null)
- JS的引用数据类型的存储(Object)
浅拷贝 深拷贝
- 浅拷贝是创建一个新对象,这个对象有着原始对象属性值得一份精确拷贝。
- 如果属性是基本数据类型,拷贝的就是这个基本类型的值。如果属性是引用数据类型,拷贝的就是内存地址。
- 所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
- 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响到原对象。
针对引用类型来说 赋值 深拷贝 浅拷贝的区别
-
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是说两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
var person = { name:'爱就一个字', hobby:['学习',['看电影','购物'],'跑步'] } //赋值 实现 var person1 = person person1.name = '艾灸两个字' person1.hobby[0] = '玩耍' console.log(person) console.log(person1) // 显示结果: 两个person 对象完全一致
-
浅拷贝:重新在堆中创建内存,拷贝前后基本数据类型互不影响,但拷贝前后对象的引用数据类型共享同一块数据内存,会相互影响。
var person = { name:'爱就一个字', hobby:['学习',['看电影','购物'],'跑步'] } // 浅拷贝的实现 function ShallowCopy(obj){ var target = {} for(var i in obj){ if(obj.hasOwnProperty(i))){ target[i] = obj[i] } } return target } var person1 = ShallowCopy(person) person1.name = '艾灸两个字' person1.hobby[0] = '玩耍' console.log(person) // person 的 name属性属于 基本数据类型所以没有改变 console.log(person1)// person1 的 hobby数组里面内容和 person 一致 都为改变后的内容
-
深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后两个对象互不影响。
function deepClone(obj){ var cloneObj = {} if(obj === null) return obj // null 的 type 是 object类型 (JS的历史遗留问题) if(obj instanceof Date) return new Date(obj) // Date 的 PrototypeOf 是否在 obj 上 if(obj instanceof RegExp) return new RegExp(obj) // RegExp 的 PrototypeOf 是否在 obj 上 if(typeof obj !== 'object') return obj // 递归结束出口 for(var i in obj){ if(obj.hasOwnProperty(i)){ cloneObj[i] = deepClone(obj[i]) // 只要是 object 类型就一直递归 } } return cloneObj } var person1 = deepClone(person) person1.name = '艾灸两个字' person1.hobby[0] = '玩耍' console.log(person) // person 保持不变 console.log(person1)// person1 保持改变后的样子
浅拷贝的实现方式
-
Object.assign( )
var obj = {} // 存储在栈里面 指向 堆 var person = { name:'爱就一个字', hobby:['学习',['看电影','购物'],'跑步'] } Object.assign(obj,person) obj.name = '111' obj.hobby[0] = '学个P' console.log(person) console.log(obj)
-
-
lodash 里面的 _.clone( ) 一个Js的原生库 里面封装的这个方法可以实现浅拷贝
-
…展开运算符
-
var obj = {} // 存储在栈里面 指向 堆 var person = { name:'爱就一个字', hobby:['学习',['看电影','购物'],'跑步'] } obj = {...person} obj.name = '111' obj.hobby[0] = '学个P' console.log(person) console.log(obj)
-
Array.prototype.concat
const arr = [1,2,{name:'tony'}] const newArr = arr.concat() newArr[1] = 5 newArr[2].name = 'Tom' console.log(arr) console.log(newArr)
-
Array.prototype.slice
const arr = [1,2,{name:'tony'}] const newArr = arr.slice() newArr[1] = 5 newArr[2].name = 'Tom' console.log(arr) console.log(newArr)
深拷贝的实现方式
-
JSON.parse(JSON.stringify())
// 使用JSON.parse实现深拷贝 缺点:不完善 Date RegExp function 类型有问题 var person1 = JSON.parse(JSON.stringfy(person))
-
递归的操作
-
Jquery中的$.extend( )方法
-
lodash里的_.cloneDeep( )方法