js中深拷贝和浅拷贝概念,并附手写代码

12,手写深拷贝

浅拷⻉:浅拷⻉指的是将⼀个对象的属性值复制到另⼀个对象,如果有的属性的值为引⽤类型的话,那么会将这个引⽤的地址复制给对象,因此两个对象会有同⼀个引⽤类型的引⽤。浅拷⻉可以使⽤ Object.assign 和展开运算符来实现。

深拷⻉:深拷⻉相对浅拷⻉⽽⾔,如果遇到属性值为引⽤类型的时候,它新建⼀个引⽤类型并将对应的值复制给它,因此对象获得的⼀个新的引⽤类型⽽不是⼀个原有类型的引⽤。深拷⻉对于⼀些对象可以使⽤ JSON 的两个函数来实现,但是由于 JSON 的对象格式⽐ js 的对象格式更加严格,所以如果属性值⾥边出现函数或者 Symbol 类型的值时,会转换失败

(1)JSON.stringify()

JSON.parse(JSON.stringify(obj)) 是⽬前⽐较常⽤的深拷⻉⽅法之⼀,它的原理就是利⽤JSON.stringify 将js 对象序列化(JSON字符串),再使⽤JSON.parse 来反序列化(还原)js 对象。

这个⽅法可以简单粗暴的实现深拷⻉,但是还存在问题,拷⻉的对象中如果有函数,undefined,symbol,当使⽤过JSON.stringify() 进⾏处理之后,都会消失。

let obj1 = { a: 0,
b: {
c: 0
}
};
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.a = 1;
obj1.b.c = 1;
console.log(obj1); // {a: 1, b: {c: 1}}
console.log(obj2); // {a: 0, b: {c: 0}}

(2)函数库lodash的_.cloneDeep⽅法

var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false

(3)手写深拷贝函数

function deepCopy(object){
               // 递归结束条件,当传进来的参数不是对象的时候,就停止递归
               if(!object || typeof object !== 'object') return
               let newObject = Array.isArray(object)?[]:{}
               // for..in 会遍历出原型对象上新增的属性和方法,所以需要使用hasOwnpropertype判断某属性是都是对象本身具有的属性
               for(let key in object){
                    if(object.hasOwnProperty(key)){
                         // 判断这个key的value值是基本数据类型还是对象,如果是对象,那继续深拷贝
                         newObject[key] = typeof object[key] === 'object'?deepCopy(object[key]) : object[key]
                    }
               }
               return newObject
          }

13,手写浅拷贝

浅拷⻉是指,⼀个新的对象对原始对象的属性值进⾏精确地拷⻉,如果拷⻉的是基本数据类型,拷⻉的就是基本数据类型的值,如果是引⽤数据类型,拷⻉的就是内存地址。如果其中⼀个对象的引⽤内存地址发⽣改变,另⼀个对象也会发⽣变化。

(1)object.assign()

Object.assign() 是ES6中对象的拷⻉⽅法,接受的第⼀个参数是⽬标对象,其余参数是源对象,

⽤法: Object.assign(target, source_1, ···) ,该⽅法可以实现浅拷⻉,也可以实现⼀维对象的深拷⻉。

注意:

  1. 如果⽬标对象和源对象有同名属性,或者多个源对象有同名属性,则后⾯的属性会覆盖前⾯的属
    性。
  2. 如果该函数只有⼀个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转
    为对象然后返回。
  3. 因为null 和 undefined 不能转化为对象,所以第⼀个参数不能为null 或 undefined ,会
    报错。

(2)扩展运算符

使⽤扩展运算符可以在构造字⾯量对象的时候,进⾏属性的拷⻉。语法: let cloneObj = {…obj };

(3)数组的方式实现

  • Array.prototype.slice()

    • slice() ⽅法是JavaScript数组的⼀个⽅法,这个⽅法可以从已有数组中返回选定的元素:

      ⽤法: array.slice(start, end) ,该⽅法不会改变原始数组.

      该⽅法有两个参数,两个参数都可选,如果两个参数都不写,就可以实现⼀个数组的浅拷⻉。

  • Array.prototype.concat()

    • concat() ⽅法⽤于合并两个或多个数组。此⽅法不会更改现有数组,⽽是返回⼀个新数组。
    • 该⽅法有两个参数,两个参数都可选,如果两个参数都不写,就可以实现⼀个数组的浅拷⻉。

(4)手写浅拷贝

// 浅拷⻉的实现;
function shallowCopy(object) {
// 只拷⻉对象
if (!object || typeof object !== "object") return;
// 根据 object 的类型判断是新建⼀个数组还是对象
let newObject = Array.isArray(object) ? [] : {};
// 遍历 object,并且判断是 object 的属性才拷⻉
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key];
}
}
return newObject;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值