javascript深拷贝(deepClone)详解


Posted in Javascript onAugust 24, 2016

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类型

javascript中有以下基本类型

类型 描述
undefined undefined类型只有一个值undefined,它是变量未被赋值时的值
null null类型也只有一个值null, 它是一个空的对象引用
Boolean Boolean有两种取值true和false
String 它表示文本信息
Number 它表示数字信息
Object 它是一系列属性的无序集合, 包括函数Function和数组Array
使用typeof是无法判断function和array的,这里使用Object.prototype.toString方法。
[默认情况下,每个对象都会从Object上继承到toString()方法,如果这个方法没有被这个对象自身或者更接近的上层原型上的同名方法覆盖(遮蔽),则调用该对象的toString()方法时会返回"[object type]",这里的字符串type表示了一个对象类型][1]

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 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类型,博主这里是直接赋值的,还是共享一个内存值。这是因为函数更多的是完成某些功能,有个输入值和返回值,而且对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝。

但是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)];
}

其它方式?

jquery的实现

详见https://github.com/jquery/jqu...

underscore的实现

详见https://github.com/jashkenas/...

lodash的实现

详见https://github.com/lodash/lod...

JSON实现

先通过JSON.stringify一下,然后再JSON.parse一下,就能实现深拷贝。但是数据类型只支持基本数值类型。

var obj = {
  a: 'a',  
  b: function(){console.log('b')}
}

//在JSON.stringify的时候就会把function给过滤了。

JSON.stringify(obj)// "{"a":"a"}"

小结

这里大概总结了一下深拷贝,以及怎么实现一个深拷贝。在不同的场景下,要根据业务场景,判断是否需要使用深拷贝。

Javascript 相关文章推荐
javascript 闭包疑问
Dec 30 Javascript
javascript获取鼠标位置部分的实例代码(兼容IE,FF)
Aug 05 Javascript
javascript数字时钟示例分享
Apr 23 Javascript
jQuery移动web开发中的页面初始化与加载事件
Dec 03 Javascript
原生js实现数字字母混合验证码的简单实例
Dec 10 Javascript
jquery 重写 ajax提交并判断权限后 使用load方法报错解决方法
Jan 19 Javascript
快速掌握jquery分页插件jqPaginator的使用方法
Aug 09 jQuery
iframe高度自适应及隐藏滚动条的实例详解
Sep 29 Javascript
详解Node.js 中使用 ECDSA 签名遇到的坑
Nov 26 Javascript
JavaScript实现学生在线做题计时器功能
Dec 05 Javascript
ES6 class类链式继承,实例化及react super(props)原理详解
Feb 15 Javascript
js+canvas实现纸牌游戏
Mar 16 Javascript
js实现无缝循环滚动
Jun 23 #Javascript
jquery实现网页定位导航
Aug 23 #Javascript
Jquery组件easyUi实现手风琴(折叠面板)示例
Aug 23 #Javascript
Javascript将JSON日期格式化
Aug 23 #Javascript
Jquery组件easyUi实现选项卡切换示例
Aug 23 #Javascript
Jquery调用iframe父页面中的元素及方法
Aug 23 #Javascript
Jquery组件easyUi实现表单验证示例
Aug 23 #Javascript
You might like
给php新手谈谈我的学习心得
2007/02/25 PHP
PHP简单系统数据添加以及数据删除模块源文件下载
2008/06/07 PHP
PHP Web木马扫描器代码分享
2015/09/06 PHP
在PHP 7下安装Swoole与Yar,Yaf的方法教程
2017/06/02 PHP
php基于session锁防止阻塞请求的方法分析
2017/08/07 PHP
CCPry JS类库 代码
2009/10/30 Javascript
jquery 关键字“拖曳搜索”之“拖曳”以及 图片“提示自适应放大”效果 的实现
2010/04/18 Javascript
JavaScript浏览器选项卡效果
2010/08/25 Javascript
深入理解JavaScript系列(12) 变量对象(Variable Object)
2012/01/16 Javascript
用示例说明filter()与find()的用法以及children()与find()的区别分析
2013/04/26 Javascript
jQuery鼠标经过方形图片切换成圆边效果代码分享
2015/08/20 Javascript
Chrome浏览器的alert弹窗禁止再次弹出后恢复的方法
2016/12/30 Javascript
tablesorter.js表格排序使用方法(支持中文排序)
2017/02/10 Javascript
详解一个基于套接字实现长连接的express
2019/03/28 Javascript
vue指令之表单控件绑定v-model v-model与v-bind结合使用
2019/04/17 Javascript
D3.js(v3)+react 实现带坐标与比例尺的散点图 (V3版本)
2019/05/09 Javascript
如何用原生js写一个弹窗消息提醒插件
2019/05/24 Javascript
JS实现横向轮播图(初级版)
2020/06/24 Javascript
Python的Django框架中settings文件的部署建议
2015/05/30 Python
用yum安装MySQLdb模块的步骤方法
2016/12/15 Python
PyTorch上搭建简单神经网络实现回归和分类的示例
2018/04/28 Python
pycharm运行和调试不显示结果的解决方法
2018/11/30 Python
详解python使用turtle库来画一朵花
2019/03/21 Python
python实现BP神经网络回归预测模型
2019/08/09 Python
Python编写一个验证码图片数据标注GUI程序附源码
2019/12/09 Python
安装pyecharts1.8.0版本后导入pyecharts模块绘图时报错: “所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 ”的解决方法
2020/08/18 Python
python 线程的五个状态
2020/09/22 Python
Python从MySQL数据库中面抽取试题,生成试卷
2021/01/14 Python
使用HTML5和CSS3表单验证功能
2017/05/05 HTML / CSS
爱尔兰灯和灯具网上商店:Lights.ie
2018/03/26 全球购物
主持词开场白
2014/03/17 职场文书
模具设计与制造专业求职信
2014/07/19 职场文书
预备党员个人总结
2015/02/14 职场文书
2015年中秋节演讲稿
2015/03/20 职场文书
2015年电厂工作总结范文
2015/05/13 职场文书
Android Rxjava3 使用场景详解
2022/04/07 Java/Android