博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于JavaScript的浅拷贝和深拷贝
阅读量:6962 次
发布时间:2019-06-27

本文共 3297 字,大约阅读时间需要 10 分钟。

前言

要理解 JavaScript中浅拷贝和深拷贝的区别,首先要明白JavaScript的数据类型。JavaScript有两种数据类型,基础数据类型和引用数据类型。

js的基本类型:undefined,null,string,boolean,number,symbol(es6新增),保存在栈内存中
js的引用类型:Object类型, Array类型,Date类型,RegExp类型,Function类型,基本包装对象(Boolean类型,Number类型,String类型),单体内置对象(Global对象,Math对象),保存在堆内存空间中

1.基本类型值和引用类型值的复制

1.1基本类型值

基本类型值是指在栈内存保存的简单数据段,在复制基本类型值的时候,会开辟出一个新的内存空间,将值复制到新的内存空间。

var a = 1;var b = a;a = 2;console.log(a);//输出2;console.log(b);//输出1;

var a = 1;

图片描述

var b = a;

图片描述

a = 2;

图片描述

从上面例子看出,当一个变量的值是基本类型,把它复制给另一个变量,复制完成后改变它的值,不会影响已经复制了它的值的变量。

1.2引用类型值

引用类型值是保存在堆内存中的对象,变量保存的只是指向该内存的地址,在复制引用类型值的时候,其实只复制了指向该内存的地址。

var a = {   name: 'Kitty',   age: '20',   sex: 'man'};var b = a;a.name = 'Jack';console.log(a);//输出{name: 'Jack',age: 20,sex: 'man'}console.log(b);//输出{name: 'Jack',age: 20,sex: 'man'}

var a = {name: ‘Kitty’,age: ‘20’,sex: ‘man’};

图片描述

var b = a;

图片描述

a.name = ‘Jack’;

图片描述

从上面例子看出,当一个变量的值是引用类型值,把它复制给另外一个变量,复制的只是指向储存对象内存的地址,所以复制完成后,改变它的值,会影响复制了它的值的变量。

注意:如果有两个变量的值是引用类型值,就算它们的值完全相同,它们也是不相等的,因为它们指向的内存地址不同,例子:

图片描述

2. 对象的浅拷贝与深拷贝

当一个变量是对象,如果像上面那样直接将一个变量赋值给另一个变量,如果改变某个变量的值,另外一个变量也会跟着改变,如果我们不想发生这种情况,就需要写一个函数用来拷贝对象。

深拷贝和浅拷贝的示意图大致如下:

图片描述

2.1 对象浅拷贝

var a = {name:'wanger'}var b = Object.assign({}, a)a===b // falseb.name = 'zhangsan'a.name //'wanger'

上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆,这时候a与b指向的是不同的栈对象,所以对b.name重新复制也不会影响到a.name。但是如果a.name是一个对象的引用,而不是一个字符串,那么上面的代码也会遇到一些问题,参考如下代码:

var a = {name:{firstName:'wang',lastName:'er'}}var b = Object.assign({}, a)a===b // falseb.name.firstName = 'zhang'a.name.firstName //'zhang'

b.name.firstName又影响到了a.name.firstName,这是因为Object.assign()方法只是浅层拷贝,a.name是一个栈对象的引用,赋值给b时,b.name也同样是这个栈对象的引用,很多时候,我们不想让这种事情发生,所以我们就需要用到对象的深拷贝。

2.2 对象深拷贝

2.2.1 万能的for循环实现对象的深拷贝

var obj = {  name: 'FungLeo',  sex: 'man',  old: '18'}var obj2 = copyObj(obj)function copyObj(obj) {  let res = {}  for (var key in obj) {    res[key] = obj[key]  }  return res}

2.2.2 JSON.parse(JSON.stringify(objectToClone))

var obj = {  name: 'FungLeo',  sex: 'man',  old: '18'}var obj2 = JSON.parse(JSON.stringify(obj))

2.2.3 扩展运算符实现对象的深拷贝

var obj = {  name: 'FungLeo',  sex: 'man',  old: '18'}var { ...obj2 } = objobj.old = '22'console.log(obj)console.log(obj2)

运行结果如下:

图片描述

3. 数组的浅拷贝与深拷贝

3.1 数组浅拷贝

var arr = ['old', 1, true, null, undefined];var new_arr = arr.concat(); // 或者var new_arr = arr.slice()也是一样的效果;new_arr[0] = 'new';console.log(arr); // ["old", 1, true, null, undefined]console.log(new_arr); // ["new", 1, true, null, undefined]

数组的浅拷贝,可用concat、slice返回一个新数组的特性来实现拷贝,但是如果数组嵌套了对象或者数组的话用concat、slice拷贝只要有修改会引起新旧数组都一起改变了,比如:

var arr = [{old: 'old'}, ['old']];var new_arr = arr.concat();arr[0].old = 'new';new_arr[1][0] = 'new';console.log(arr); // [{old: 'new'}, ['new']]console.log(new_arr); // [{old: 'new'}, ['new']]

如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化。这种叫浅拷贝 。

深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。

3.2 数组深拷贝

3.2.1 利用扩展运算符...对数组中嵌套对象进行深拷贝

var arr=[{a:1,b:2},{c:1,d:2}];    var arr2=[];        arr.forEach(item=>{      var {...obj}=item;      arr2.push(obj);    })    arr2[1].d=7        console.log(arr,arr2)

图片描述

3.2.2 利用lodash库的cloneDeep方法

var arr=[{a:1,b:2},{c:1,d:2}];var arr2=_.cloneDeep(arr)   arr2[1].d=7;console.log(arr,arr2)

图片描述

3.2.3 JSON.parse(JSON.stringify(objectToClone))

var arr=[{a:1,b:2},{c:1,d:2}];var arr2=JSON.parse(JSON.stringify(arr));    arr2[1].d=7;console.log(arr,arr2)

图片描述

转载地址:http://zowsl.baihongyu.com/

你可能感兴趣的文章
JAVA 枚举妙用
查看>>
MySQL在线导出文件报错
查看>>
QCon所见和所得:杭州QCon热门技术话题分享
查看>>
图表(Chart & Graph)你真的用对了吗?
查看>>
做好软件项目验收管理4步走
查看>>
有关dubbo线程池溢出
查看>>
springmvc框架
查看>>
安装Spket插件到Eclipse
查看>>
学习笔记(四)——目录命令、rm 等常用命令、查看文本命令、文件属性
查看>>
Vue知识点整理
查看>>
python笔试题---实践知识点
查看>>
spring boot 2.x data redis 使用也太简单了吧
查看>>
php超时时间说明
查看>>
spring cron表达式及解析过程
查看>>
MyBatis(二)-----注解方式crud
查看>>
navicat连接腾讯云MySQL
查看>>
嵌入式Linux加快物联网开发速度的方案研究
查看>>
java程序员如何拿到2万月薪
查看>>
redis常用命令总结
查看>>
ActiveMQ —— <一> 概述
查看>>