JS中的两种数据类型及实现引用类型的深拷贝的方法


Posted in Javascript onAugust 12, 2018

一.前言

我们知道,在JS中数据类型按照访问方式和存储方式的不同可分为基本类型和引用类型。

基本类型

基本类型有String、Boolean、Number,Undefined、Null,这些基本类型都是按值传递的,也称为值类型。

引用类型

引用类型有对象、数组、函数,它们都是按引用访问的。

二.存储方式区别

基本类型和引用类型由于两者在内存中存储的方式不同,造成两者访问的方式也不同。其中,基本类型存储在内存的栈中,是按值访问;引用类型存储在内存的堆中,是按引用访问。可如下图所示:

当有

var n1 = 10;
 var n2 = 10;
 var arr1 = [1,2,3,4]
 var arr2 = [1,2,3,4]

其在内存中存储方式如图:

JS中的两种数据类型及实现引用类型的深拷贝的方法

值类型是在栈中直接保存的变量的实际值,而引用类型在栈中仅仅保存的是变量指向堆中的地址,从上图中可以看出,值类型的变量n1和n2都是10,但是在栈中却为这两个变量分别开辟了两块空间来存储,而引用类型的变量arr1和arr2也相同,但是在堆中仅仅开辟了一块内存来存储,而在栈中存储的是这两个变量指向堆中的地址,这两个变量都指向堆中的同一片地址。

三.拷贝区别

正是由于两者在存储方式上的不同,造成了两者在拷贝时的差异。首先,先看两段代码:

var n1 = 10;
 //将n1拷贝给n2
 var n2 = n1;
 n1 = 12;
 console.log(n1);
 console.log(n2);

先定义变量n1=10,然后将n1拷贝给n2,再接着改变n1的值为12,分别打印n1和n2的值,打印结果为:

JS中的两种数据类型及实现引用类型的深拷贝的方法

从结果中我们可以看到,n1变为12了,但是n2不受影响,依旧是10。

再看另外一段代码:

var arr1 = [1,2,3,4]
 //将arr1拷贝给arr2
 var arr2 = arr1;
 //向arr1中尾部添加一个元素5
 arr1.push(5); 
 console.log(arr1);
 console.log(arr2);

先定义数组arr1,然后将arr1拷贝给arr2,再接着向arr1中尾部追加一个元素,分别打印arr1和arr2的值,打印结果为:

JS中的两种数据类型及实现引用类型的深拷贝的方法

从结果中我们可以看到:我们先将arr1拷贝给了arr2,但是当我们改变arr1时,arr2也跟着一起改变了。这印证了前文所说的,arr1和arr2实际上是指向了内存中的同一片地址,当arr1发生变化时,实际上是将指向的这片内存地址中的数据变化了,而arr2也指向的是这片地址,所以arr2也会跟着变化。

上面代码中的arr2=arr1,就是我们俗称的浅拷贝,浅拷贝仅仅拷贝的是变量名,其在内存的存储没有被拷贝,指向的还是同一片内存地址,这就是造成了一个变化另外一个也跟着变化,这在日常开发中不是我们想要的。

那如何实现真正的拷贝呢?

四.实现深拷贝

真正的拷贝,就是拷贝过后,arr1和arr2指向的不再是同一片内存地址,而是分别指向各自的地址,这样发生变化的时候就不会出现同时变化,这就是深拷贝。

下面我们封装一个深拷贝函数,来实现引用类型的深拷贝:

//参数p为原对象
 //参数c为原对象的类型,若原对象为数组,则传入c为[],若原对象是对象传入c为{},也可不传默认为{}
 function deepCopy(p,c){
 var c = c || {};
 for(var i in p){
 if(typeof p[i] === "object"){
 

c[i] = (p[i].constructor === Array)?[]:{};
 

deepCopy(p[i],c[i])
 

}else{
 

c[i] = p[i]

  }
 
}
 
return c;
 }

五.测试

//参数p为原对象
 //参数c为原对象的类型,若原对象为数组,则传入c为[],若原对象是对象传入c为{},也可不传默认为{}
 function deepCopy(p,c){
 var c = c || {};
 for(var i in p){
 if(typeof p[i] === "object"){
 

 c[i] = (p[i].constructor === Array)?[]:{};
 

 deepCopy(p[i],c[i])
 

}else{
 


c[i] = p[i]
 

}
 
}
 
return c;
 }
 //定义数组arr1
 var arr1 = [1,2,3,4]
 //将arr1拷贝给arr2
 var arr2 = deepCopy(arr1,[]);
 //向arr1中尾部添加一个元素5
 arr1.push(5);
 console.log('arr1:',arr1);
 console.log('arr2:',arr2);

测试结果:

JS中的两种数据类型及实现引用类型的深拷贝的方法

结果中可以看到,arr1变化没有引起arr2的变化,实现了真正的拷贝。

总结

以上所述是小编给大家介绍的JS中的两种数据类型及实现引用类型的深拷贝的方法,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
新浪微博字数统计 textarea字数统计实现代码
Aug 28 Javascript
javascript中有趣的反柯里化深入分析
Dec 05 Javascript
js取模(求余数)隔行变色
May 15 Javascript
Javascript 运动中Offset的bug解决方案
Dec 24 Javascript
基于JavaScript实现鼠标悬浮弹出跟随鼠标移动的带箭头的信息层
Jan 18 Javascript
jQuery轮播图效果精简版完整示例
Sep 04 Javascript
Angular2+如何去除url中的#号详解
Dec 20 Javascript
详解js中Array的方法及技巧
Sep 12 Javascript
微信小程序 swiper 组件遇到的问题及解决方法
May 26 Javascript
vue如何在用户要关闭当前网页时弹出提示的实现
May 31 Javascript
antd 表格列宽自适应方法以及错误处理操作
Oct 27 Javascript
解决VUE项目使用Element-ui 下拉组件的验证失效问题
Nov 07 Javascript
原生JS封装_new函数实现new关键字的功能
Aug 12 #Javascript
axios向后台传递数组作为参数的方法
Aug 11 #Javascript
让axios发送表单请求形式的键值对post数据的实例
Aug 11 #Javascript
axios的拦截请求与响应方法
Aug 11 #Javascript
解决axios发送post请求返回400状态码的问题
Aug 11 #Javascript
vue 组件的封装之基于axios的ajax请求方法
Aug 11 #Javascript
解决Vue axios post请求,后台获取不到数据的问题方法
Aug 11 #Javascript
You might like
thinkphp3.2.2实现生成多张缩略图的方法
2014/12/19 PHP
使用图灵api创建微信聊天机器人
2015/07/23 PHP
PHP如何将log信息写入服务器中的log文件
2015/07/29 PHP
PHP仿微信发红包领红包效果
2016/10/30 PHP
YII2自动登录Cookie总是失效的解决方法
2017/06/28 PHP
ThinkPHP3.1.x修改成功与失败跳转页面的方法
2017/09/29 PHP
在 Laravel 中动态隐藏 API 字段的方法
2019/10/25 PHP
浅谈php常用的7大框架的优缺点
2020/07/20 PHP
javascript 日期时间 转换的方法
2013/02/21 Javascript
Google官方支持的NodeJS访问API,提供后台登录授权
2014/07/29 NodeJs
JavaScript 开发工具webstrom使用指南
2014/12/09 Javascript
jQuery使用prepend()方法在元素前添加内容用法实例
2015/03/26 Javascript
js对字符串进行编码的方法总结(推荐)
2016/11/10 Javascript
bootstrap表格分页实例讲解
2016/12/30 Javascript
js获取一组日期中最近连续的天数
2017/05/25 Javascript
js设置随机切换背景图片的简单实例
2017/11/12 Javascript
node简单实现一个更改头像功能的示例
2017/12/29 Javascript
js点击时关闭该范围下拉菜单之外的菜单方法
2018/01/11 Javascript
JS数组实现分类统计实例代码
2018/09/30 Javascript
vue项目中使用Svg的方法
2018/10/24 Javascript
vue-router的使用方法及含参数的配置方法
2018/11/13 Javascript
详解小程序中h5页面onShow实现及跨页面通信方案
2019/05/30 Javascript
Layui表格监听行单双击事件讲解
2019/11/14 Javascript
JavaScript实现HSL拾色器
2020/05/21 Javascript
JS性能优化实现方法及优点进行
2020/08/30 Javascript
python基于FTP实现文件传输相关功能代码实例
2019/09/28 Python
python opencv 图像边框(填充)添加及图像混合的实现方法(末尾实现类似幻灯片渐变的效果)
2020/03/09 Python
Python 如何实现数据库表结构同步
2020/09/29 Python
CSS3教程(10):CSS3 HSL声明设置颜色
2009/04/02 HTML / CSS
iPad和Surface Pro蓝牙键盘:Brydge
2018/11/10 全球购物
澳大利亚设计师服装在线:MISHA
2019/10/07 全球购物
2019年c语言经典面试题目
2016/08/17 面试题
Static Nested Class 和 Inner Class的不同
2013/11/28 面试题
项目总经理岗位职责
2014/02/14 职场文书
生产工厂门卫岗位职责
2014/09/26 职场文书
学习十八届四中全会依法治国心得体会
2014/11/03 职场文书