浅拷贝和深拷贝的方法(浅拷贝与深拷贝)
在JavaScript中存在两大数据类型:基本类型 、引用类型 。
基本数据类型存放在栈中 ,是一段简单的数据段 ,数据大小确定 ,内存空间大小可以分配 ,是直接按值存放的 ,可以按值访问 。
引用数据类型存放在堆中 ,变量在栈中保存的是指向堆内存的地址值 ,这个地址值指向对应的对象类型 ,访问堆内存中的对象是通过地址值访问的 。
二 、浅拷贝浅拷贝 ,指的是创建新的数据 ,这个数据有着原始数据属性值的一份精确拷贝 。
如果属性是基本类型 ,拷贝的就是基本类型的值 。如果属性是引用类型 ,拷贝的就是内存地址 。
即浅拷贝是拷贝一层 。
下面简单实现一个浅拷贝:
function shallowClone (obj) { const newObj = {} for (let prop in obj) { if (obj.hasOwnProperty(prop)) { newObj[prop] = obj[prop] } } return newObj }在JavaScript中,存在浅拷贝的现象有:
Object.assign() Array.prototype.slice() Array.prototype.concat() 使用扩展运算符实现的复制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({}, fxObj)slice()
const fxArr = [One, Two, Three] const fxArrs = fxArr.slice(0) fxArrs[1] = love consloe.log(fxArr) // [One, Two, Three] consloe.log(fxArrs) // [One, love, Three]concat()
const fxArr = [One, Two, Three] const fxArrs = fxArr.concat() fxArrs[1] = love consloe.log(fxArr) // [One, Two, Three] consloe.log(fxArrs) // [One, love, Three]扩展运算符
const fxArr = [One, Two, Three] const fxArrs = [...fxArr] fxArrs[1] = love consloe.log(fxArr) // [One, Two, Three] consloe.log(fxArrs) // [One, love, Three] 三 、深拷贝深拷贝开辟一个新的栈 ,两个对象相同 ,但是对应两个不同的地址,修改一个对象的属性 ,不会改变另一个对象的属性 。
常见的深拷贝方式有:
_.cloneDeep() jQuery.extend() 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) // falsejQuery.extend()
const $ = require(jquery) const obj1 = { a: 1, b: { f: { g: 1 } }, c: { 1, 2, 3 } } const obj2 = $.extend(true, {}, obj1) console.log(obj1.b.f === obj2.b.f) // falseJSON.stringify()
const obj = { name: A, name1: undefined, name2: function () {}, name3: Symbol(A) } const obj2 = JSON.parse(JSON.stringify(obj1)) // 会忽略undefined 、Symbol 、函数 console.log(obj2) // { name: A }循环递归
function deepClone (obj, hash = new WeakMap()) { if (obj === null) return obj // 如果是null或者undefined ,就不进行拷贝操作 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 } 四 、区别浅拷贝只复制内存地址 ,而不复制对象本身 ,新旧对象还是共享同一块内存 ,修改对象属性会影响原对象 。
// 浅拷贝 const obj1 = { name: init, arr: [1, [2, 3], 4] } const obj3 = shallowClone(obj1) // 一个浅拷贝方法 obj3.name = update‘ obj3.arr[1] = [5, 6, 7] // 新旧对象还是共享同一块内存 console.log(obj1, obj1) // obj1 { name: init, arr: [1, [5, 6, 7], 4] } console.log(obj3, obj3) // obj3 { name: update, arr: [1, [5, 6, 7], 4] }深拷贝会另外创造一个一模一样的对象 ,新对象与原对象不共享内存 ,修改新对象不会改到原对象 。
// 深拷贝 const obj1 = { name: init, arr: [1, [2, 3], 4] } const obj4 = deepClone(obj1) // 一个深拷贝方法 obj4.name = update‘ obj4.arr[1] = [5, 6, 7] // 新对象与原对象不共享内存 console.log(obj1, obj1) // obj1 { name: init, arr: [1, [2, 3], 4] } console.log(obj4, obj4) // obj4 { name: update, arr: [1, [5, 6, 7], 4] }当拷贝类型为引用类型时:
浅拷贝是拷贝一层 ,属性为对象时 ,浅拷贝是复制,两个对象指向同一个地址 。 深拷贝是递归拷贝深层次 ,属性为对象时 ,深拷贝是新开栈,两个对象指向不同的地址 。创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!