js对象的深拷贝和浅拷贝
来源:互联网 发布:淘宝食品备案流程图 编辑:程序博客网 时间:2024/05/17 06:58
为啥要用深拷贝?
在很多情况下,我们都需要给变量赋值,给内存地址赋值,但是在赋引用类型值的时候,只是共享同一个内存区域,导致赋值的时候,还跟之前的值保持一致性。
看一个具体的例子
// 给test赋值了一个对象var test = { a: 'a', b: 'b'};// 将test赋值给test2// 此时test和test2是共享了同一块内存对象,这也就是浅拷贝var test2 = test;test2.a = 'a2';test.a === 'a2'// 为true
图解:
这下就很好理解为什么引用值类型数据相互影响问题。
实现
实现一个深拷贝函数,就不得不说javascript的数值类型。
判断javascript类型
javascript中有以下基本类型
使用typeof是无法判断function和array的,这里使用Object.prototype.toString方法。 默认情况下,每个对象都会从Object上继承到toString()方法,如果这个方法没有被这个对象自身或者更接近的上层原型上的同名方法覆盖(遮蔽),则调用该对象的toString()方法时会返回”[object type]”,这里的字符串type表示了一个对象类型
function type(obj) {var toString = Object.prototype.toString;var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object'};return map[toString.call(obj)];}
实现deepClone
对于非引用值类型的数值,直接赋值,而对于引用值类型(object)还需要再次遍历,递归赋值。
简洁版的深拷贝
function clone(Obj) { var buf; if (Obj instanceof Array) { buf = []; // 创建一个空的数组 var i = Obj.length; while (i--) { buf[i] = clone(Obj[i]); } return buf; } else if (Obj instanceof Object){ buf = {}; // 创建一个空对象 for (var k in Obj) { // 为这个对象添加新的属性 buf[k] = clone(Obj[k]); } return buf; }else{ return Obj; }}
区别在于:对对象和数组类型判断
function deepClone(data) { var t = Object.prototype.toString.call(data), o, i, len; if(t === '[object Array]') { o = []; for (i = 0, len = data.length; i < len; i++) { o.push(deepClone(data[i])); } return o; }else if( t === '[object Object]') { o = {}; for( i in data) { o[i] = deepClone(data[i]); } return o; }else { return data; }}
这里有个点大家要注意下,对于function类型,博主这里是直接赋值的,还是共享一个内存值。这是因为函数更多的是完成某些功能,有个输入值和返回值,而且对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝。
但是function类型要怎么拷贝呢?
其实博主只想到了用new来操作一下,但是function就会执行一遍,不敢想象会有什么执行结果哦!o(╯□╰)o!其它暂时还没有什么好的想法,欢迎大家指导哦!
到这里差不多也就实现完了深拷贝,又有人觉的怎么没有实现浅拷贝呢?
对于浅拷贝而言,可以理解为只操作一个共同的内存区域!这里会存在危险!(。﹏。*) 。
如果直接操作这个共享的数据,不做控制的话,会经常出现数据异常,被其它部分更改。所以应该不要直接操作数据源,给数据源封装一些方法,来对数据来进行CURD操作。
到这里估计就差不多了,但是作为一个前端,不仅仅考虑javascript本身,还得考虑到dom、浏览器等。
Element类型
来看下面代码,结果会返回啥呢?
Object.prototype.toString.call(document.getElementsByTagName(‘div’)[0])
答案是[object HTMLDivElement]
有时候保存了dom元素, 一不小心进行深拷贝,上面的深拷贝函数就缺少了对Element元素的判断。而判断Element元素要使用instanceof来判断。因为对于不同的标签,tostring会返回对应不同的标签的构造函数。
function type(obj) { var toString = Object.prototype.toString; var map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; if(obj instanceof Element) { return 'element'; } return map[toString.call(obj)];}
其它方式?
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一下,就能实现深拷贝。但是数据类型只支持基本数值类型。
var obj = { a: 'a', b: function(){console.log('b')}}//在JSON.stringify的时候就会把function给过滤了。JSON.stringify(obj)// "{"a":"a"}"
小结
这里大概总结了一下深拷贝,以及怎么实现一个深拷贝。在不同的场景下,要根据业务场景,判断是否需要使用深拷贝。
参考文献
文献一:winter-JavaScript中的类型 http://www.cnblogs.com/winter-cn/archive/2009/12/07/1618281.html
文献二:www.alloyteam.com/2017/08/12978/
转自:
伯乐在线/前端-小强
- js 对象浅拷贝和深拷贝
- js对象的浅拷贝和深拷贝
- js对象的深拷贝和浅拷贝
- js对象的深拷贝和浅拷贝
- 对象的深拷贝和浅拷贝
- js的深拷贝和浅拷贝
- Python对象的拷贝,浅拷贝和深拷贝。
- js对象深拷贝和淺拷贝
- js对象浅拷贝和深拷贝详解
- js对象浅拷贝和深拷贝详解
- JS数组和对象的深拷贝
- js 对象和数组的深拷贝
- js对象浅拷贝与深拷贝
- js 对象浅拷贝、深拷贝
- object c的浅拷贝(地址拷贝)和深拷贝(对象拷贝)
- js中对象的复制,浅复制(浅拷贝)和深复制(深拷贝)
- c#的对象的深拷贝和浅拷贝
- JS对象的深拷贝
- 谁将引领新一代视频编码标准:HEVC、AVS2、AV1性能对比报告
- 1085. Perfect Sequence (25)
- MongoDB菜鸟入门(一):概念与增删改查、建立索引
- python调用线程
- struts2学习笔记 -- day02 struts2主配置文件详解
- js对象的深拷贝和浅拷贝
- 下载spring网站的相关文档pdf版本
- 基于docker的GPU测试方法
- 编程思想——第二章
- QT笔记(1)——信号&槽机制,事件
- 积性函数的性质及证明 + 线性筛
- MySql卸载重新安装出现Start service没有响应的解决办法(64位)
- struts2学习笔记 -- day03 struts2整合hibernate环境搭建
- 前端的一些插件和框架的CDN引用