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 相关文章推荐
jQuery编程中的一些核心方法简介
Aug 14 Javascript
Hallo.js基于jQuery UI所见即所得的Web编辑器
Jan 26 Javascript
JavaScript SHA1加密算法实现详细代码
Oct 06 Javascript
js事件源window.event.srcElement兼容性写法(详解)
Nov 25 Javascript
Angular-Touch库用法示例
Dec 22 Javascript
JavaScript实现简单生成随机颜色的方法
Sep 21 Javascript
jQuery除指定区域外点击任何地方隐藏DIV功能
Nov 13 jQuery
vue.js使用v-if实现显示与隐藏功能示例
Jul 06 Javascript
vue debug 二种方法
Sep 16 Javascript
vue 子组件和父组件传值的示例
Sep 11 Javascript
vue实现按钮切换图片
Jan 20 Vue.js
JavaScript 反射学习技巧
Oct 16 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
PHP简洁函数小结
2011/08/12 PHP
php生成随机数的三种方法
2014/09/10 PHP
完美利用Yii2微信后台开发的系列总结
2016/07/18 PHP
PHP实现创建微信自定义菜单的方法示例
2017/07/14 PHP
PHP convert_cyr_string()函数讲解
2019/02/13 PHP
Laravel框架模型的创建及模型对数据操作示例
2019/05/07 PHP
thinkphp5.1 框架钩子和行为用法实例分析
2020/05/25 PHP
给网站上的广告“加速”显示的方法
2007/04/08 Javascript
firefox中用javascript实现鼠标位置的定位
2007/06/17 Javascript
javascript 出生日期和身份证判断大全
2008/11/13 Javascript
jQuery 行级解析读取XML文件(附源码)
2009/10/12 Javascript
js动态给table添加/删除tr的方法
2013/08/02 Javascript
Js实现双击鼠标自动滚动屏幕的示例代码
2013/12/14 Javascript
一些老手都不一定知道的JavaScript技巧
2014/05/06 Javascript
QQ空间顶部折页撕开效果示例代码
2014/06/15 Javascript
jQuery对val和atrr("value")赋值的区别介绍
2014/09/26 Javascript
使用Bootrap和Vue实现仿百度搜索功能
2017/10/26 Javascript
mint-ui的search组件在键盘显示搜索按钮的实现方法
2017/10/27 Javascript
webstorm中vue语法的支持详解
2018/05/09 Javascript
深入解析vue 源码目录及构建过程分析
2019/04/24 Javascript
element-ui树形控件后台返回的数据+生成组织树的工具类
2020/03/05 Javascript
javascript解析json格式的数据方法详解
2020/08/07 Javascript
[03:20]2015国际邀请赛全明星表演赛
2015/08/08 DOTA
python中的字典操作及字典函数
2018/01/03 Python
python多线程http压力测试脚本
2019/06/25 Python
Pytorch基本变量类型FloatTensor与Variable用法
2020/01/08 Python
在Pytorch中使用Mask R-CNN进行实例分割操作
2020/06/24 Python
pycharm 配置svn的图文教程(手把手教你)
2021/01/15 Python
html5 跨文档消息传输示例探讨
2013/04/01 HTML / CSS
公司清洁工岗位职责
2013/12/14 职场文书
公司门卫岗位职责
2014/03/15 职场文书
《雕塑之美》教学反思
2014/04/24 职场文书
公司离职证明样本
2014/09/13 职场文书
MongoDB balancer的使用详解
2021/04/30 MongoDB
python opencv通过4坐标剪裁图片
2021/06/05 Python
Kubernetes部署实例并配置Deployment、网络映射、副本集
2022/04/01 Servers