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

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

时间2025-09-19 04:26:31分类IT科技浏览5523
导读:一、前言 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
百度高级研发工程师名单(核心技术研发工程师 百度在线网络技术(北京)有限公司 庞果网Pongo.cn)