javascript中的深复制
2016-09-06 12:22
330 查看
javascript深拷贝是初学者甚至有经验的开发着,都会经常遇到问题,并不能很好的理解javascript的深拷贝。
深拷贝(deepClone)是神马,与深拷贝相对应的就是浅拷贝,刚开始我也没弄懂。
在很多情况下,我们都需要给变量赋值,给内存地址赋予一个值,但是在赋值引用值类型的时候,只是共享一个内存区域,导致赋值的时候,还跟之前的值保持一直性。
看一个具体的例子
如下图:
这下就很好理解为什么引用值类型数据相互影响问题。
实现一个深拷贝函数,就不得不说javascript的数值类型。下面我们先来看一个js有哪几种数据类型:
使用
默认情况下,每个对象都会从Object上继承到
我们先写一个
现在已经很清楚了,如何实现深复制呢,对于非引用类型的数值,直接赋值,而对于引用类型的值(
这里有个点大家要注意下,对于
浅拷贝,对于浅拷贝而言,可以理解为只操作一个共同的内存区域!这里会存在危险!
如果直接操作这个共享的数据,不做控制的话,会经常出现数据异常,被其它部分更改。所以应该不要直接操作数据源,给数据源封装一些方法,来对数据来进行CURD操作。
到这里估计就差不多了,但是作为一个前端,不仅仅考虑javascript本身,还得考虑到dom、浏览器等。
Element类型,来看下面代码,结果会返回啥呢?
经过测试,返回的是:
有时候保存了dom元素, 一不小心进行深拷贝,上面的深拷贝函数就缺少了对
深拷贝(deepClone)是神马,与深拷贝相对应的就是浅拷贝,刚开始我也没弄懂。
在很多情况下,我们都需要给变量赋值,给内存地址赋予一个值,但是在赋值引用值类型的时候,只是共享一个内存区域,导致赋值的时候,还跟之前的值保持一直性。
看一个具体的例子
// 给test赋值了一个对象 var test = { a: 'a', b: 'b' }; // 将test赋值给test2 // 此时test和test2是共享了同一块内存对象,这也就是浅拷贝 var test2 = test; test2.a = 'a2'; test.a === 'a2'// 为true
如下图:
这下就很好理解为什么引用值类型数据相互影响问题。
实现一个深拷贝函数,就不得不说javascript的数值类型。下面我们先来看一个js有哪几种数据类型:
类型 | 描述 |
---|---|
undefined | undefined类型只有一个值undefined,它是变量未被赋值时的值 |
null | null类型也只有一个值,它是一个空对象的引用 |
Boolean | Boolean有两种值true和false |
String | 字符串类型 |
Number | 数字类型,包括整数和浮点数 |
Object | 它是一系列属性的无序集合,包括函数Function和数组Array |
typeof是无法判断
function和
array的,使用
instanceof在多个
iframe里也会出错,我们可以使用
Object.prototype.toString方法,它可判断出各种类型。
默认情况下,每个对象都会从Object上继承到
toString()方法,如果这个方法没有被这个对象自身或者更接近的上层原型上的同名方法覆盖(遮蔽),则调用该对象的
toString()方法时会返回
[object type],这里的字符串
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)]; }
现在已经很清楚了,如何实现深复制呢,对于非引用类型的数值,直接赋值,而对于引用类型的值(
object)需要多次遍历,递归复制。
function deepClone(data) { var t = type(data), o, i, ni; if(t === 'array') { o = []; }else if( t === 'object') { o = {}; }else { return data; } if(t === 'array') { for (i = 0, ni = data.length; i < ni; i++) { o.push(deepClone(data[i])); } return o; }else if( t === 'object') { for( i in data) { o[i] = deepClone(data[i]); } return o; } }
这里有个点大家要注意下,对于
function类型,这里是直接赋值的,还是共享一个内存值。这是因为函数更多的是完成某些功能,有个输入值和返回值,而且对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝。
浅拷贝,对于浅拷贝而言,可以理解为只操作一个共同的内存区域!这里会存在危险!
如果直接操作这个共享的数据,不做控制的话,会经常出现数据异常,被其它部分更改。所以应该不要直接操作数据源,给数据源封装一些方法,来对数据来进行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)]; }
相关文章推荐
- javascript复制函数
- 通过JavaScript脚本复制网页上的一个表格
- Javascript 实现复制到粘贴板
- JavaScript屏蔽右键和复制
- 使用Javascript操作DOM的一些方法--元素的访问/复制等
- 「JavaScript」梅花雪日历控件3.0-直接复制代码保存为html格式即可运行
- javascript实现从Excel文件向Web表单的某列多行数据复制
- 用javascript 禁止右键,禁止复制,禁止粘贴
- 很棒的javascript防复制代码
- 最新JavaScript炸弹!(把代码复制在地址栏上玩也可以炸死你!)
- 一段多浏览器的"复制到剪贴板"javascript代码
- 复制本网址给好友(javascript)
- 网页不能复制 Javascript
- 一段多浏览器的"复制到剪贴板"javascript代码
- clone方法完成javascript中数组的复制
- 通过JavaScript脚本复制网页上的一个表格
- 用 javascript 实现的点击复制代码
- 禁止用户复制网页内容(JavaScript)
- javascript实现复制功能
- Javascript----文件操作(删除/复制/剪贴...)