首页IT科技js深拷贝与浅拷贝的区别(JavaScript 深拷贝和浅拷贝)

js深拷贝与浅拷贝的区别(JavaScript 深拷贝和浅拷贝)

时间2025-05-05 14:56:13分类IT科技浏览3358
导读:一、前言 hello,大家好~ ,本文主要介绍在 JavaScript 中什么是深拷贝和浅拷贝,以及如何实现一个对象的深拷贝。...

一           、前言

hello           ,大家好~                 ,本文主要介绍在 JavaScript 中什么是深拷贝和浅拷贝     ,以及如何实现一个对象的深拷贝           。

二                、随处可见的 “赋值           ”

在 JavaScript 中我们最常见的操作之一是将一个变量的值赋值给另一个变量      ,这个过程我们也可以称为 “拷贝                ” 一份变量的值给另一个变量                。

2.1 基本数据类型的赋值操作

在涉及到基本数据类型(string     、Boolean      、number...)赋值操作的时候                ,原始变量值被复制给另外一个变量     。我们来考虑下下面这段代码:我们将值为 10 的变量 x 赋值给变量 y           ,此时 x 和 y 已经失去“联系     ”了      ,所以改变 x 的值不会影响 y 的值                ,最后输出 20 和 10      。

<script> let x = 10; let y = x; x += 10; console.log(x, y); // 20 10 </script>

2.2 引用数据类型的赋值操作

与基本数据类型赋值相反           ,引用数据类型(Object                、Array...)在赋值的时候传递的只是一个 引用 (原始值和拷贝赋值后的值指向同一块内存空间) ,所以当被复制出来的对象值改变的时候                ,原始的对象值也会跟着改变                ,这种现象被称为 浅拷贝                 。

对象赋值案例: 将 user 对象赋值给 user2 变量,修改 user2 属性值后 user 属性值也会跟着变           ,两者的值始终保持同步                ,这便是浅拷贝带来的 副作用      ,拷贝出来的值和原始值始终保持着关联           。基本数据类型的赋值没有这种现象           ,所以说 浅拷贝深拷贝 是相对引用数据类型而言的      。

<script> let user = { name: zjl712, age: 18, local: shanghai } let user2 = user; user2.name = zjl; console.log(user:, user, user2:, user2); </script>

三           、实现对象的深拷贝

通过以上的介绍我们知道什么是 浅拷贝 以及浅拷贝带来的 副作用                 ,为了消除这种“副作用      ”我们需要对对象进行 深拷贝                 。下面将介绍一些对象拷贝的方法     ,它们各有优缺点           。

"=" 号直接赋值

通过等号(=)将原始值赋值给一个新的值      ,优点是简便快捷                ,缺点 是只能进行 浅拷贝

let obj = {name:zjl712, age:18} let obj2 = obj; console.log(obj == obj2) //true Object.assign()

通过 Object 的 assign 方法可以对对象进行深拷贝           ,缺点是不能对含有多层嵌套结构的对象进行深拷贝。

深拷贝单层结构的对象      ,改变拷贝对象的值不会改变原始对象的值                。

<script> let obj = { name: zjl712, age: 18, getName:function(){ return this.name } } let obj2 = Object.assign({}, obj) console.log(obj == obj2); // false obj2.name = zjl console.log(obj, obj2); </script>

尝试拷贝多层嵌套结构对象                ,改变拷贝对象内嵌套的对象值(obj2.local.nickname)后,原始对象嵌套的值也会跟着改变                。改变拷贝对象非嵌套的值           ,原始对象的值不会跟着变。所以 Object.assign() 只能实现部分深拷贝           。

<script> let obj = { name: zjl712, age: 18, getName:function(){ return this.name }, local: { name: shanghai, nickname: modu, } } let obj2 = Object.assign({}, obj) console.log(obj == obj2); // false obj2.local.nickname = 魔都 obj2.name = zjl console.log(obj, obj2); console.log(obj.local == obj2.local) // true </script> JSON.stringify() 和 JSON.parse()

JSON.stringify() 方法接收一个对象作为参数,将对象转为 JSON 字符串                。JSON.parse() 接收一个 JSON 字符串                ,将该字符串转为一个对象     。结合这两个方法可以对一个对象进行深拷贝           。

结合以上两个方法对对象进行深拷贝

let obj = {name: zjl712,age: 18} let obj2 = JSON.parse(JSON.stringify(obj)) console.log(obj == obj2); // false obj2.name = zjl console.log(obj, obj2);

当对象属性值含有 函数(function) 时,且含有嵌套对象时                。拷贝的值 属性值为函数的属性会丢失      。优点是能对多层嵌套对象进行深拷贝      。

let obj = { name: zjl712, age: 18, getName:function(){ return this.name }, local: { name: shanghai, nickname: modu, } } let obj2 = JSON.parse(JSON.stringify(obj)) console.log(obj == obj2); // false obj2.local.nickname = 魔都 obj2.name = zjl console.log(obj, obj2); console.log(obj.local == obj2.local) // false 对象扩展符(...)

使用 ES6 的扩展操作符                ,使用三个点(...)将原始对象的值拷贝给另一个对象                。然而三点扩展符和 Object.assign() 很相似,扩展符不能对多层嵌套对象进行深拷贝           。

let obj = { name: zjl712, age: 18, getName:function(){ return this.name }, local: { name: shanghai, nickname: modu, } } let obj2 = {...obj} console.log(obj == obj2); // false obj2.local.nickname = 魔都 obj2.name = zjl console.log(obj, obj2); 递归的方式实现对象的深拷贝

实现含有嵌套结构      、函数对象的深拷贝以上方法都无能为力           ,我们可以用递归的方法完成对象的深拷贝      。缺点是对复杂的对象(Buffer                、Date 等实例对象)无法实现深拷贝

function myDeepClone(obj){ let clone; // 排除非引用类型数据 if(obj == null || typeof obj != object) return obj; if(Array.isArray(obj)){ // obj 是数组 clone = new obj.constructor(obj.length) obj.forEach((value, index) => { clone[index] = typeof value === object?myDeepClone(value):value }) }else{ // 浅拷贝一份原始数据 clone = Object.assign({}, obj) // 递归 clone 内的每一个属性值 Object.keys(clone).forEach(key => { clone[key] = typeof obj[key] === object?myDeepClone(obj[key]):obj[key] }) } return clone; }

以上递归代码有相似代码(两个 forEach 内的代码)                ,可简化为以下代码:

function myDeepClone(obj){ let clone; if(obj == null || typeof obj != object) return obj; clone = Object.assign({}, obj) Object.keys(clone).forEach(key => { clone[key] = typeof obj[key] === object?myDeepClone(obj[key]):obj[key] }) if(Array.isArray(obj)){ clone.length = obj.length clone = Array.from(clone) } return clone } 以上的自定义递归方法不够全面     ,但对于基本的对象( {} )和数组( [] )深拷贝还是够用的           ,要想实现复杂对象的深拷贝可以使用 lodashcloneDeep 方法                ,这个方法实现深拷贝是比较完美的                。 // 安装 lodash :npm i lodash // 使用 let lang = require(lodash/lang) let clone = lang.cloneDeep(obj)

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
34909百家论坛959l23(“ 百家论坛 ” – ChatGPT)