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 相关文章推荐
jquery制作select列表双向选择示例代码
Sep 02 Javascript
使用javascript实现json数据以csv格式下载
Jan 09 Javascript
jquery加载图片时以淡入方式显示的方法
Jan 14 Javascript
JavaScript对HTML DOM使用EventListener进行操作
Oct 21 Javascript
JavaScript事件学习小结(五)js中事件类型之鼠标事件
Jun 09 Javascript
通过BootStrap实现轮播图的实际应用
Sep 26 Javascript
javascript中call,apply,bind函数用法示例
Dec 19 Javascript
easyui-datagrid特殊字符不能显示的处理方法
Apr 12 Javascript
react开发教程之React 组件之间的通信方式
Aug 12 Javascript
小程序页面动态配置实现方法
Feb 05 Javascript
详解为element-ui的Select和Cascader添加弹层底部操作按钮
Feb 07 Javascript
three.js欧拉角和四元数的使用方法
Jul 26 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
配置支持SSI
2006/11/25 PHP
巧用php中的array_filter()函数去掉多维空值的代码分享
2012/09/07 PHP
PHP 7安装调试工具Xdebug扩展的方法教程
2017/06/17 PHP
php微信开发之图片回复功能
2018/06/14 PHP
PHP论坛实现积分系统的思路代码详解
2020/06/01 PHP
utf8的编码算法 转载
2006/12/27 Javascript
javascript第一课
2007/02/27 Javascript
extjs 学习笔记(一) 一些基础知识
2009/10/13 Javascript
JavaScript 学习笔记(十二) dom
2010/01/21 Javascript
jquery地址栏链接与a标签链接匹配之特效代码总结
2015/08/24 Javascript
javascript省市级联功能实现方法实例详解
2015/10/20 Javascript
基于JQuery实现图片轮播效果(焦点图)
2016/02/02 Javascript
Angular2表单自定义验证器的实现
2016/10/19 Javascript
JS用斜率判断鼠标进入DIV四个方向的方法
2016/11/07 Javascript
javascript实现简单的可随机变色网页计算器示例
2016/12/30 Javascript
利用纯JS实现像素逐渐显示的方法示例
2017/08/14 Javascript
微信小程序wx:for和wx:for-item的用法详解
2018/04/01 Javascript
Vue2.0中三种常用传值方式(父传子、子传父、非父子组件传值)
2018/08/16 Javascript
Angular2中监听数据更新的方法
2018/08/31 Javascript
vue2.0 可折叠列表 v-for循环展示的实例
2018/09/07 Javascript
JS实现的冒泡排序,快速排序,插入排序算法示例
2019/03/02 Javascript
vue实现PC端录音功能的实例代码
2019/06/05 Javascript
JS前端面试必备——基本排序算法原理与实现方法详解【插入/选择/归并/冒泡/快速排序】
2020/02/24 Javascript
python操作excel文件并输出txt文件的实例
2018/07/10 Python
python中pytest收集用例规则与运行指定用例详解
2019/06/27 Python
使用Python和OpenCV检测图像中的物体并将物体裁剪下来
2019/10/30 Python
python科学计算之numpy——ufunc函数用法
2019/11/25 Python
让IE支持CSS3的不完全兼容方案
2014/09/19 HTML / CSS
娇韵诗加拿大官网:Clarins加拿大
2017/11/20 全球购物
美国最大的电子宠物训练产品制造商:PetSafe
2018/10/12 全球购物
计算机专业学生的自我评价
2013/12/15 职场文书
中国梦演讲稿范文
2014/08/28 职场文书
信用卡催款律师函
2015/05/27 职场文书
2016教师六五普法学习心得体会
2016/01/21 职场文书
MySQL 十大常用字符串函数详解
2021/06/30 MySQL
解析MySQL索引的作用
2022/03/03 MySQL