Javascript深拷贝

Javascript深拷贝

大家好,又见面了,我是全栈君。

Javascript深拷贝

javascript深拷贝是初学者甚至有经验的开发者,都会经常遇到问题,并不能很好的理解javascript的深拷贝。

深拷贝(deepClone)?

与深拷贝相对的就是浅拷贝,很多初学者在接触这个感念的时候,是很懵逼的。

Javascript深拷贝

为啥要用深拷贝?

在很多情况下,我们都需要给变量赋值,给内存地址赋予一个值,但是在赋值引用值类型的时候,只是共享一个内存区域,导致赋值的时候,还跟之前的值保持一直性。

看一个具体的例子

 
  1. // 给test赋值了一个对象 
  2.  
  3. var test = { 
  4.  
  5. a: ‘a’
  6.  
  7. b: ‘b’ 
  8.  
  9. }; 
  10.  
  11.   
  12.  
  13. // 将test赋值给test2 
  14.  
  15. // 此时test和test2是共享了同一块内存对象,这也就是浅拷贝 
  16.  
  17. var test2 = test; 
  18.  
  19.   
  20.  
  21. test2.a = ‘a2’
  22.  
  23.   
  24.  
  25. test.a === ‘a2’// 为true  

图解:

Javascript深拷贝

这下就很好理解为什么引用值类型数据相互影响问题。

实现

实现一个深拷贝函数,就不得不说javascript的数值类型。

判断javascript类型

javascript中有以下基本类型

类型 描述
undefined undefined类型只有一个值undefined,它是变量未被赋值时的值
null null类型也只有一个值null, 它是一个空的对象引用
Boolean Boolean有两种取值true和false
String 它表示文本信息
Number 它表示数字信息
Object 它是一系列属性的无序集合, 包括函数Function和数组Array

使用typeof是无法判断function和array的,这里使用Object.prototype.toString方法。 默认情况下,每个对象都会从Object上继承到toString()方法,如果这个方法没有被这个对象自身或者更接近的上层原型上的同名方法覆盖(遮蔽),则调用该对象的toString()方法时会返回”[object type]”,这里的字符串type表示了一个对象类型

 
  1. function type(obj) { 
  2.  
  3. var toString = Object.prototype.toString; 
  4.  
  5. var map = { 
  6.  
  7.     ‘[object Boolean]’  : ‘boolean’
  8.  
  9.     ‘[object Number]’   : ‘number’
  10.  
  11.     ‘[object String]’   : ‘string’
  12.  
  13.     ‘[object Function]’ : ‘function’
  14.  
  15.     ‘[object Array]’    : ‘array’
  16.  
  17.     ‘[object Date]’     : ‘date’
  18.  
  19.     ‘[object RegExp]’   : ‘regExp’
  20.  
  21.     ‘[object Undefined]’‘undefined’
  22.  
  23.     ‘[object Null]’     : ‘null’
  24.  
  25.     ‘[object Object]’   : ‘object’ 
  26.  
  27. }; 
  28.  
  29. return map[toString.call(obj)]; 
  30.  
  31. }  

实现deepClone

对于非引用值类型的数值,直接赋值,而对于引用值类型(object)还需要再次遍历,递归赋值。

 
  1. function deepClone(data) { 
  2.  
  3. var t = type(data), o, i, ni; 
  4.  
  5. if(t === ‘array’) { 
  6.  
  7.     o = []; 
  8.  
  9. }else if( t === ‘object’) { 
  10.  
  11.     o = {}; 
  12.  
  13. }else { 
  14.  
  15.     return data; 
  16.  
  17.  
  18. if(t === ‘array’) { 
  19.  
  20.     for (i = 0, ni = data.length; i < ni; i++) { 
  21.  
  22.         o.push(deepClone(data[i])); 
  23.  
  24.     } 
  25.  
  26.     return o; 
  27.  
  28. }else if( t === ‘object’) { 
  29.  
  30.     for( i in data) { 
  31.  
  32.         o[i] = deepClone(data[i]); 
  33.  
  34.     } 
  35.  
  36.     return o; 
  37.  
  38.  
  39. }  

这里有个点大家要注意下,对于function类型,博主这里是直接赋值的,还是共享一个内存值。这是因为函数更多的是完成某些功能,有个输入值和返回值,而且对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝。

但是function类型要怎么拷贝呢?

其实博主只想到了用new来操作一下,但是function就会执行一遍,不敢想象会有什么执行结果哦!o(╯□╰)o!其它暂时还没有什么好的想法,欢迎大家指导哦!

到这里差不多也就实现完了深拷贝,又有人觉的怎么没有实现浅拷贝呢?

浅拷贝?

对于浅拷贝而言,可以理解为只操作一个共同的内存区域!这里会存在危险!(。﹏。*) 。

如果直接操作这个共享的数据,不做控制的话,会经常出现数据异常,被其它部分更改。所以应该不要直接操作数据源,给数据源封装一些方法,来对数据来进行CURD操作。

到这里估计就差不多了,但是作为一个前端,不仅仅考虑javascript本身,还得考虑到dom、浏览器等。

Element类型

来看下面代码,结果会返回啥呢?

 
  1. Object.prototype.toString.call(document.getElementsByTagName(‘div’)[0]) 

答案是[object HTMLDivElement]

有时候保存了dom元素, 一不小心进行深拷贝,上面的深拷贝函数就缺少了对Element元素的判断。而判断Element元素要使用instanceof来判断。因为对于不同的标签,tostring会返回对应不同的标签的构造函数。

 
  1. function type(obj) { 
  2.  
  3. var toString = Object.prototype.toString; 
  4.  
  5. var map = { 
  6.  
  7.     ‘[object Boolean]’  : ‘boolean’
  8.  
  9.     ‘[object Number]’   : ‘number’
  10.  
  11.     ‘[object String]’   : ‘string’
  12.  
  13.     ‘[object Function]’ : ‘function’
  14.  
  15.     ‘[object Array]’    : ‘array’
  16.  
  17.     ‘[object Date]’     : ‘date’
  18.  
  19.     ‘[object RegExp]’   : ‘regExp’
  20.  
  21.     ‘[object Undefined]’‘undefined’
  22.  
  23.     ‘[object Null]’     : ‘null’
  24.  
  25.     ‘[object Object]’   : ‘object’ 
  26.  
  27. }; 
  28.  
  29. if(obj instanceof Element) { 
  30.  
  31.         return ‘element’
  32.  
  33.  
  34. return map[toString.call(obj)]; 
  35.  
  36. }  

其它方式?

1. jquery的实现

详见https://github.com/jquery/jquery/blob/master/src/core.js

2. underscore的实现

详见https://github.com/jashkenas/underscore/blob/master/underscore.js

3. lodash的实现

详见https://github.com/lodash/lodash/blob/master/lodash.js

4. JSON实现

先通过JSON.stringify一下,然后再JSON.parse一下,就能实现深拷贝。但是数据类型只支持基本数值类型。

 
  1. var obj = { 
  2.  
  3.     a: ‘a’,     
  4.  
  5.     b: function(){console.log(‘b’)} 
  6.  
  7.  
  8.   
  9.  
  10. //在JSON.stringify的时候就会把function给过滤了。 
  11.  
  12.   
  13.  
  14. JSON.stringify(obj)// “{“a“:”a“}”  

小结

这里大概总结了一下深拷贝,以及怎么实现一个深拷贝。在不同的场景下,要根据业务场景,判断是否需要使用深拷贝。

作者:佚名

来源:51CTO

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/108288.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • debian10 中文乱码_ue中文乱码解决方案

    debian10 中文乱码_ue中文乱码解决方案系统版本:Debian6.0.2Squeeze产生乱码原因:系统没有中文字体解决方案:1、从win下拷贝后缀为ttf的字体库到/usr/share/fonts/truetype/,我这里拷贝MSYH.ttf(微软雅黑)。2、终端输入一下代码:   #su

    2022年10月18日
  • Java操作MongoDB

    Java操作MongoDB

  • Python网络爬虫精要

    Python网络爬虫精要

  • 什么叫做公网IP_是不是公网ip

    什么叫做公网IP_是不是公网ip由于公网ip资源匮乏,NAT(地址转换)技术被广泛应用。其好处就是让更多的电脑能够上网,缺点在于你自己搭建了一台服务器。想实现远程访问,如果服务器的地址如果是经过NAT转换后的地址,外网是无法访问到的。这就引出了公网ip和私网ip的概念,可以通过开头的数字来判断ip地址的类型,下面就给大家普及一下。由于私网ip地址仅限于局域网内使用,并且是可以重复的,所以IANA当初划分了一些网段,专供局域网内使用。具体网段如下:10.x.x.x192.168.x.x172.16.x.x-172.3

    2022年10月21日
  • iphone相册打开是横屏_苹果手机相册变成横屏怎么办

    iphone相册打开是横屏_苹果手机相册变成横屏怎么办1.在以往开发中,app调用相册一直没问题。最近开发ipad的时候,项目必须横屏,这时候调用相册的时候app就奔溃了问题所在:系统的相册只支持竖屏打开,如果你的app设置了只能横屏,就会冲突,打不开相册,程序会崩溃。解决方法:在网上找了很久,很多说在打开相册的时候强制竖屏,或者重写一个类,继承UIImagePickerController,重写他的 –

  • 配置二层交换机Vlan_华为模拟器交换机配置

    配置二层交换机Vlan_华为模拟器交换机配置二层交换机VLAN基础配置

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号