javascript中的深复制详解及实例分析


Posted in Javascript onDecember 29, 2016

 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中的深复制详解及实例分析

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

       实现一个深拷贝函数,就不得不说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 相关文章推荐
经验几则 推荐
Sep 05 Javascript
基于jQuery实现左右div自适应高度完全相同的代码
Aug 09 Javascript
JavaScript中的稀疏数组与密集数组[译]
Sep 17 Javascript
Jquery attr(&quot;checked&quot;) 返回checked或undefined 获取选中失效
Oct 10 Javascript
字符串反转_JavaScript
Apr 28 Javascript
JS对大量数据进行多重过滤的方法
Nov 04 Javascript
详解AngularJS中$filter过滤器使用(自定义过滤器)
Feb 04 Javascript
Javascript中的prototype与继承
Feb 06 Javascript
JS通过调用微信API实现微信支付功能的方法示例
Jun 29 Javascript
vue2组件之select2调用的示例代码
Oct 12 Javascript
JavaScript实现星级评价效果
May 17 Javascript
关于vue利用postcss-pxtorem进行移动端适配的问题
Nov 20 Javascript
canvas学习之API整理笔记(一)
Dec 29 #Javascript
Javascript Function.prototype.bind详细分析
Dec 29 #Javascript
jQuery自定义插件详解及实例代码
Dec 29 #Javascript
canvas快速绘制圆形、三角形、矩形、多边形方法介绍
Dec 29 #Javascript
JavaScript获取短信验证码(周期性)
Dec 29 #Javascript
JavaScript实现同一个页面打开多张图片
Dec 29 #Javascript
Javascript 对cookie操作详解及实例
Dec 29 #Javascript
You might like
Oracle Faq(Oracle的版本)
2006/10/09 PHP
修改PHP的memory_limit限制的方法分享
2012/02/21 PHP
ThinkPHP入库出现两次反斜线转义及数据库类转义的解决方法
2014/11/04 PHP
PHP+MySQL之Insert Into数据插入用法分析
2015/09/27 PHP
详解WordPress中调用评论模板和循环输出评论的PHP函数
2016/01/05 PHP
如何通过PHP实现Des加密算法代码实例
2020/05/09 PHP
javascript 打印页面代码
2009/03/24 Javascript
jQuery 获取对象 根据属性、内容匹配, 还有表单元素匹配
2010/05/31 Javascript
JS左右无缝滚动(一般方法+面向对象方法)
2012/08/17 Javascript
jQuery关于导航条背景切换效果实现示例
2013/09/04 Javascript
JavaScript的事件绑定(方便不支持js的时候)
2013/10/01 Javascript
js 日期比较相关天数代码
2014/04/02 Javascript
JavaScript基于对象去除数组重复项的方法
2016/10/09 Javascript
浅谈JavaScript的计时器对象
2016/12/26 Javascript
js数字计算 误差问题的快速解决方法
2017/02/28 Javascript
微信小程序实现多选删除列表数据功能示例
2019/01/15 Javascript
webpack项目使用eslint建立代码规范实现
2019/05/16 Javascript
Layui之table中的radio在切换分页时无法记住选中状态的解决方法
2019/09/02 Javascript
微信小程序按钮点击动画效果的实现
2019/09/04 Javascript
bootstrap+spring boot实现面包屑导航功能(前端代码)
2019/10/09 Javascript
JS访问对象两种方式区别解析
2020/08/29 Javascript
微信跳一跳python辅助软件思路及图像识别源码解析
2018/01/04 Python
python3.5+tesseract+adb实现西瓜视频或头脑王者辅助答题
2018/01/17 Python
python中正则表达式 re.findall 用法
2018/10/23 Python
python 引用传递和值传递详解(实参,形参)
2020/06/05 Python
聚美优品的广告词
2014/03/14 职场文书
关于运动会的口号
2014/06/07 职场文书
就业协议书样本
2014/08/20 职场文书
四风问题对照检查材料思想汇报
2014/10/07 职场文书
小学一年级学生评语大全
2014/12/25 职场文书
呼啸山庄读书笔记
2015/06/29 职场文书
《富饶的西沙群岛》教学反思
2016/02/16 职场文书
2019最新婚庆对联集锦!
2019/07/10 职场文书
八年级地理课件资料及考点知识分享
2019/08/30 职场文书
python3 实现mysql数据库连接池的示例代码
2021/04/17 Python
go select编译期的优化处理逻辑使用场景分析
2021/06/28 Golang