javascript中的深复制
JavaScript深拷贝是初学者甚至有经验的开发着,都会经常遇到问题,并不能很好的理解javascript的深拷贝。
深拷贝(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)]; }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
本文向大家介绍C++对象的浅复制和深复制详解及简单实例,包括了C++对象的浅复制和深复制详解及简单实例的使用技巧和注意事项,需要的朋友参考一下 C++对象的浅复制和深复制详解及简单实例 浅复制:两个对象复制完成后共享某些资源(内存),其中一个对象的销毁会影响另一个对象 深复制:两个对象复制完成后不会共享任何资源,其中一个对象的销毁不会影响另一个对象 下面我们来看一段代码,以便直观的理解: 这段程序
本文向大家介绍MySQL 复制详解及简单实例,包括了MySQL 复制详解及简单实例的使用技巧和注意事项,需要的朋友参考一下 MySQL 复制详解及简单实例 主从复制技术在MySQL中被广泛使用,主要用于同步一台服务器上的数据至多台从服务器,可以用于实现负载均衡,高可用和故障切换,以及提供备份等等。MySQL支持多种不同的复制技术,诸如单向,半同步异步复制等以及不同级别的复制,诸如数据库级别,表级
本文向大家介绍详解JavaScript对象的深浅复制,包括了详解JavaScript对象的深浅复制的使用技巧和注意事项,需要的朋友参考一下 前言 从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性。 在复制对象时,除了要复制对象的属性外,还要兼顾到是否保留了对象的construct
本文向大家介绍php5对象复制、clone、浅复制与深复制实例详解,包括了php5对象复制、clone、浅复制与深复制实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了php5对象复制、clone、浅复制与深复制。分享给大家供大家参考,具体如下: 对象复制的由来 为什么对象会有“复制”这个概念,这与PHP5中对象的传值方式是密切相关的,让我们看看下面这段简单的代码 PHP代码 这段代
本文向大家介绍MySQL 复制表详解及实例代码,包括了MySQL 复制表详解及实例代码的使用技巧和注意事项,需要的朋友参考一下 MySQL 复制表详解 如果我们需要完全的复制MySQL的数据表,包括表的结构,索引,默认值等。 如果仅仅使用CREATE TABLE ... SELECT 命令,是无法实现的。 本章节将为大家介绍如何完整的复制MySQL数据表,步骤如下: 使用 SHOW CREATE
本文向大家介绍JavaScript 闭包机制详解及实例代码,包括了JavaScript 闭包机制详解及实例代码的使用技巧和注意事项,需要的朋友参考一下 首先要区分两个概念,一是匿名函数,一是闭包。 所谓匿名函数,就是创建函数没有给定函数名。经常出现的包括函数表达式,就是定义一个匿名函数,然后将函数赋值给某个变量,而此时这个变量就相当于该函数的函数名,例如: 还有一种常用匿名函数的情况是回调函数,如