浅拷贝和深拷贝

浅拷贝的方法
Object.assign()
  • 方法可以将任意多个源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象
Object.assign()
const obj = {
	name: 'xiaolizi',
	age: 20,
	sex: '男'
}
const newObj = Object.assign({}, obj)
const obj1 =  Object.assign(obj, {name: 'newxiaolizi', age: 25})
console.log(newObj.name, obj1) 

注意点:

  • 它不会拷贝对象里的继承属性
  • 它不会拷贝对象里的不可枚举属性
  • 可以拷贝Symbol类型属性
使用扩展运算符实现浅拷贝
let source = {
    name: 'Marry',
    info: {
        age: 20
    }
}
const nameInfos = {...source}

nameInfos.info.age = 24
console.log(source)
  • 上述代码和使用Object.assign功能相同,其注意事项也相同,两者在使用上基本是可以相互转换
Array.prototype.concat
  • 数组中的concat方法其实也是浅拷贝,使用场景比较少,当用concat连接的数组含有引用类型数据,要注意修改原数组中元素属性,会影响到concat连接产生的新数组。
let student={
    name:"Lily",
    age:15,
    sex:"女",
    friends:["Jack","Rose","Ben"]
}
let obj5=Array.prototype.concat.call({}, student, {school: 'xiaoxue'})
student.friends[0] = 'Marry'
student.age = 20
console.log(obj5) //{name: "Lily", age: 20, sex: "女", friends: Array(3)} 

对象中age变成20,friends的jack变成Marry。

Array.prototype.slice()
  • 数组中slice方法也是浅拷贝,使用场景比较少,同concat
const arr = [1, 2, {name: 'li'}]
const newArr = arr.slice()
newArr[2].name = 'Tom'
console.log(arr, newArr)

arr数组中name的value值变成Tom

使用第三方库&手动实现
  • lodash工具库提供的clone的方法供用户浅拷贝
    浅拷贝的核心在于:
  • 基础数据类型直接拷贝数据
  • 引用数据类型仅拷贝第一层对象的属性,复制的就是内存中的地址(深拷贝与浅拷贝的重要差异)
const clone = function (target) {
    if(typeof target === 'Object' && target !== null) {
        let cloneTarget = Array.isArray(target)? [] : {}
        for(let prop in target) {
            if(target.hasOwnProperty(prop)){
                cloneTarget[prop] = target[prop]
            }
        }
        return cloneTarget
    }else {
        return target
    }
}
let arr = [1, 2, 3, {name: 'Tom'}]
let newArr = clone(arr)
console.log(newArr)
newArr[3].name = 'Marry'
newArr[2].name = 6
console.log(arr)
深拷贝
  • 深拷贝是将一个对象从内存中完整的拷贝出一份,从内存中开辟出一个新的区域来存放新对象,新对象跟原对象不共享内存,修改新对象不会影响原对象。
JSON.parse(JSON.stringify())
const obj = {
	name: 'xiaolizi',
	age: 20,
	sex: '男'
}
const newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)
newObj.name = 'newxiaolizi'
console.log(obj.name, newObj.name)

  1. 借助工具lodash库来深拷贝
  2. 利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的内存空间,实现深拷贝。
  3. 这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),对象中的方法克隆不到。
const obj = {
	name: 'xiaolizi',
	age: 20,
	sex: '男',
	say(){
	console.log(goodBey)
}
}
obj.say()
const newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)
newObj.say()

JSON.stringify需要注意的点

  • 拷贝对象如果有函数,undefined, symbol这几种类型,经过JSON.stringify系列化之后的字符串中的键值对会消失。
  • 拷贝Date引用类型会变成字符串
  • 无法拷贝不可枚举的属性
  • 无法拷贝对象的原型链
  • 拷贝RegExp引用类型会变成空对象
  • 对象中含有NAN,infinity以及-infinity,JSON.stringify系列化后会转换成null
  • 无法拷贝对象的循环应用,既对象成环 (obj[key] = obj)
递归
function deepClone(oldObj, hash = new WeakMap()) {
  if (oldObj === null) return oldObj; 
  // 如果是null或者undefined我就不进行拷贝操作
  if (oldObj instanceof Date) return new Date(oldObj);
  if (oldObj instanceof RegExp) return new RegExp(oldObj);
  // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
  if (typeof oldObj !== "object") return oldObj;
  // 是对象的话就要进行深拷贝
  if (hash.get(oldObj)) return hash.get(oldObj);
  let cloneObj = new oldObj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
  hash.set(oldObj, cloneObj);
  for (let key in oldObj) {
    if (oldObj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(oldObj[key], hash);
    }
  }
  return cloneObj;
}
let oldObj = { name: 1, address: { x: 100 } };
oldObj.o = oldObj; // 对象存在循环引用的情况
let d = deepClone(oldObj);
oldObj.address.x = 200;
console.log(d);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值