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 相关文章推荐
jquery中$(#form :input)与$(#form input)的区别
Aug 18 Javascript
Javascript基础教程之函数对象和属性
Jan 18 Javascript
javascript绘制漂亮的心型线效果完整实例
Feb 02 Javascript
JS实现复制内容到剪贴板功能兼容所有浏览器(推荐)
Jun 17 Javascript
JavaScript基础知识点归纳(推荐)
Jul 09 Javascript
原生js实现返回顶部缓冲效果
Jan 18 Javascript
关于在vue-cli中使用微信自动登录和分享的实例
Jun 22 Javascript
node实现简单的反向代理服务器
Jul 26 Javascript
利用express启动一个server服务的方法
Sep 17 Javascript
原生js中ajax访问的实例详解
Sep 19 Javascript
vue中使用echarts制作圆环图的实例代码
Jul 27 Javascript
解决IOS端微信H5页面软键盘弹起后页面下方留白的问题
Jun 05 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学习资源和链接.
2006/12/05 PHP
PHP序列号生成函数和字符串替换函数代码
2012/06/07 PHP
PHP让数组中有相同值的组成新的数组实例
2017/12/31 PHP
PHP实现的操作数组类库定义与用法示例
2019/05/24 PHP
Laravel框架Auth用户认证操作实例分析
2019/09/29 PHP
用window.location.href实现刷新另个框架页面
2007/03/07 Javascript
JavaScript中的object转换函数toString()与valueOf()介绍
2014/12/31 Javascript
详解javascript跨浏览器事件处理程序
2016/03/27 Javascript
20分钟轻松创建自己的Bootstrap站点
2016/05/12 Javascript
js封装tab标签页实例分享
2016/12/19 Javascript
JS实现复制内容到剪贴板功能
2017/02/05 Javascript
zTree树形插件异步加载方法详解
2017/06/14 Javascript
老生常谈Bootstrap媒体对象
2017/07/06 Javascript
用JS编写一个函数,返回数组中重复出现过的元素(实例)
2017/09/14 Javascript
JavaScript引用类型Function实例详解
2018/08/09 Javascript
微信小程序封装的HTTP请求示例【附升级版】
2019/05/11 Javascript
OpenLayers实现图层切换控件
2020/09/25 Javascript
使用vue3重构拼图游戏的实现示例
2021/01/25 Vue.js
Python写的一个简单监控系统
2015/06/19 Python
python的构建工具setup.py的方法使用示例
2017/10/23 Python
python安装模块如何通过setup.py安装(超简单)
2018/05/05 Python
NumPy.npy与pandas DataFrame的实例讲解
2018/07/09 Python
python 保存float类型的小数的位数方法
2018/10/17 Python
django+mysql的使用示例
2018/11/23 Python
pybind11在Windows下的使用教程
2019/07/04 Python
Python上下文管理器类和上下文管理器装饰器contextmanager用法实例分析
2019/11/07 Python
编程实现去掉XML的重复结点
2014/05/28 面试题
硕士研究生个人求职信
2013/12/04 职场文书
毕业生自荐信
2013/12/14 职场文书
2014年教师培训的自我评价
2014/01/03 职场文书
文明村镇申报材料
2014/05/06 职场文书
金融系应届毕业生求职信
2014/05/26 职场文书
企业环保标语
2014/06/10 职场文书
村道德模范事迹材料
2014/08/28 职场文书
高一军训的心得体会
2014/09/01 职场文书
导游词之凤凰古城
2019/10/22 职场文书