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

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

时间2025-08-01 05:42:54分类IT科技浏览4801
导读:一、前言 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
网创能学到什么(网创什么项目好-宝妈、大学生、待业者可做的网创项目) how to properly please yourself(How to properly use relative or absolute imports in Python modules? Stack Overflow)