JS 对象的深拷贝和浅拷贝

2022-12-19 0 780

现像

他们先上看两个demo

// 他们先言明两个表达式str1, // 接着把表达式str1负数(复本)给表达式str2 // 最终对表达式str2展开修正操作方式 var str1 = shen var str2 = str1 str2 += zhiyong console.log(str1:, str1) //shen console.log(str2:, str2) //shenzhiyong

他们言明两个第一类并对它展开完全相同的操作方式

var obj1 = { name: shen } var obj2 = obj1 obj2.name = shenzhiyong //期望输出 // obj1: {name: “shen”} // obj2: {name: “shenzhiyong”} console.log(obj1:, obj1) // obj1: {name: “shenzhiyong”} console.log(obj2:, obj2) // obj2: {name: “shenzhiyong”}

他们不难发现结果并不是他们预期的那样, 这是为什么呢?如果将obj1改成数组第一类展开操作方式,亦是同样的结果。

原因:由于String类型属于基本数据类型,Object(Array)属于引用数据类型。当他们言明两个基本类型并对它展开赋值的时候,计算机会将值保存在栈内存中。而当他们言明两个引用数据类型并对它展开赋值的时候,计算机会将值保存在堆内存中,引用类型表达式其实就是两个指针指向堆内存中。如果复制两完全相同的引用类型表达式,其实它们最终指向同两个第一类或者说堆内存空间。

关于JavaScript的数据类型 他们先埋下两个坑!

一、浅复本

第一类和数组的浅复本代码如下:

var obj1 = { name: shen } var obj2 = obj1 obj2.name = shenzhiyong console.log(obj1:, obj1) // obj1: {name: “shenzhiyong”} console.log(obj2:, obj2) // obj2: {name: “shenzhiyong”} var arr1 = [1,2,3] var arr2 = arr1 arr2.push(4) console.log(arr1:, arr1) // arr1: [1,2,3,4] console.log(arr2:, arr2) // arr2: [1,2,3,4]

浅复本的意思就是只复制引用,没有复制真正的值。有时候他们只是想保留第一类的数据,单纯想改变obj2和arr2的值,但是原第一类的数据也发生了改变。很多时候这种情况都不是他们想要的。为了解决这个问题: 深复本它来了!

二、深复本

JSON方法

var obj1 = { name: shen } var obj2 = JSON.parse(JSON.stringify(obj1)) obj2.name = shenzhiyong console.log(obj1:, obj1) // obj1: {name: “shen”}console.log(obj2:, obj2) // obj2: {name: “shenzhiyong”}

优点:简单明了,方便记忆

缺点:看下面代码。当第一类里面出现函数的时候就不适用了。

var obj1 = { name: shen, show: function (argument) { console.log(1) } } var obj2 = JSON.parse(JSON.stringify(obj1)) console.log(obj1:, obj1) // obj1: {name: “shen”, show: ƒ} console.log(obj2:, obj2) // obj2: {name: “shen”}

手写递归方法

function deepCopy(obj) { var newobj = obj.constructor === Array ? [] : {}; if (typeof obj !== object) { return obj; } else { for (var i in obj) { if (typeof obj[i] === object){ //判断第一类的这条属性是否为第一类 newobj[i] = deepCopy(obj[i]); //若是第一类展开嵌套调用 }else{ newobj[i] = obj[i]; } } } return newobj; //返回深度克隆后的第一类 } var obj1 = { name: shen, show: function (argument) { console.log(1) } } var obj2 = deepCopy(obj1) console.log(obj1:, obj1) // obj1: {name: “shen”, show: ƒ} console.log(obj2:, obj2) // obj2: {name: “shen”}

优点:能够实现第一类和数组的深复本

缺点:如果复本的第一类嵌套过深的话,会对性能有一定的消耗

第三方库 jQuery.extend 和 lodash

$.extend( true, object1, object2 ); // 深度复本 $.extend( object1, object2 ); // 浅复本 var objects = [{ a: 1 }, { b: 2 }]; var deep = _.cloneDeep(objects); console.log(deep[0] === objects[0]); // => false

大佬写的东西,我只能说:逃

JS 对象的深拷贝和浅拷贝

三、重点来了:具有局限性的深复本(有些面试官就喜欢问这个地方的东西)

当第一类或者数组内部的都是基本数据类型的话,以下的方式可以实现深复本。但是如果出现了引用类型嵌套引用类型的话。以下方法将不可用。

JS 对象的深拷贝和浅拷贝

看下面代码:

var obj = { name: shen } var obj2 = { innner: { name: shen } }

以下方法仅支持obj此类第一类的深度复本不支持obj2此类第一类

es6解析结构 「…」

var obj1 = { name: shen, show: function (argument) { console.log(1) } } var obj2 = { obj1 } obj2.name = shenzhiyong console.log(obj1:, obj1) // obj {name: “szy”, show: ƒ} console.log(obj2:, obj2) // obj2 {name: “shenzhiyong”, show: ƒ}

Object.assign()

var obj1 = { name: shen, show: function (argument) { console.log(1) } } var obj2 = Object.assign({} ,obj1) // 一定要写target obj2.name = shenzhiyong console.log(obj1:, obj1) // obj {name: “szy”, show: ƒ}console.log(obj2:, obj2) // obj2 {name: “shenzhiyong”, show: ƒ}

数组中的slice() & concat()

var arr1 = [1,2,3] var arr2 = arr1.slice() // 方法一 // var arr2 = arr1.concat() //方法二 arr2.push(4) console.log(arr1:, arr1) // arr1: [1, 2, 3] console.log(arr2:, arr2) // arr1: [1, 2, 3, 4]

总结:要想实现真正意义的深复本,个人觉得还是递归的方法比较靠谱。其实看第三方的库也是采用这样的做法。在实际的生产当中,我使用的是lodash。

放水完毕!

JS 对象的深拷贝和浅拷贝

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务