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 相关文章推荐
js 走马灯简单实例
Nov 21 Javascript
多选列表框动态添加,移动,删除,全选等操作的简单实例
Jan 13 Javascript
jQuery 2.0.3 源码分析之core(一)整体架构
May 27 Javascript
EasyUI Pagination 分页的两种做法小结
Jul 09 Javascript
Bootstrap基本组件学习笔记之input输入框组(9)
Dec 07 Javascript
使用vue中的v-for遍历二维数组的方法
Mar 07 Javascript
bootstrap中selectpicker下拉框使用方法实例
Mar 22 Javascript
浅谈mvvm-simple双向绑定简单实现
Apr 18 Javascript
解决vue admin element noCache设置无效的问题
Nov 12 Javascript
ES2020 已定稿,真实场景案例分析
May 25 Javascript
SpringBoot+Vue开发之Login校验规则、实现登录和重置事件
Oct 19 Javascript
antd多选下拉框一行展示的实现方式
Oct 31 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
PHP ajax 异步执行不等待执行结果的处理方法
2015/05/27 PHP
PHP 实现公历日期与农历日期的互转换
2017/09/13 PHP
php实现登录页面的简单实例
2019/09/29 PHP
js 在定义的时候立即执行的函数表达式(function)写法
2013/01/16 Javascript
node.js 开发指南 ? Node.js 连接 MySQL 并进行数据库操作
2014/07/29 Javascript
Javascript学习笔记之函数篇(五) : 构造函数
2014/11/23 Javascript
jquery利用拖拽方式在图片上添加热链接
2015/11/24 Javascript
JavaScript浏览器对象之一Window对象详解
2016/06/03 Javascript
jquery根据一个值来选中select下的option实例代码
2016/08/29 Javascript
Bootstrap基本插件学习笔记之标签切换(17)
2016/12/08 Javascript
JS中事件冒泡和事件捕获介绍
2016/12/13 Javascript
vue项目刷新当前页面的三种方法
2018/12/04 Javascript
微信小程序new Date()方法失效问题解决方法
2019/07/29 Javascript
基于JS抓取某高校附近共享单车位置 使用web方式展示位置变化代码实例
2019/08/27 Javascript
jquery实现弹窗(系统提示框)效果
2019/12/10 jQuery
python 从远程服务器下载东西的代码
2013/02/10 Python
Python中实现从目录中过滤出指定文件类型的文件
2015/02/02 Python
Python实现股市信息下载的方法
2015/06/15 Python
Python的Socket编程过程中实现UDP端口复用的实例分享
2016/03/19 Python
Python 自动刷博客浏览量实例代码
2017/06/14 Python
python中模块的__all__属性详解
2017/10/26 Python
Python实现的基数排序算法原理与用法实例分析
2017/11/23 Python
Tensorflow之Saver的用法详解
2018/04/23 Python
Python访问MongoDB,并且转换成Dataframe的方法
2018/10/15 Python
python开发准备工作之配置虚拟环境(非常重要)
2019/02/11 Python
pandas基于时间序列的固定时间间隔求均值的方法
2019/07/04 Python
keras 权重保存和权重载入方式
2020/05/21 Python
详解如何使用Pytest进行自动化测试
2021/01/14 Python
AC Lens:购买隐形眼镜
2017/02/26 全球购物
销售人员求职的自我评价分享
2014/03/15 职场文书
交通事故案件代理词
2015/05/23 职场文书
电影圆明园观后感
2015/06/03 职场文书
飞越疯人院观后感
2015/06/09 职场文书
护理心得体会范文
2016/01/22 职场文书
Vue接口封装的完整步骤记录
2021/05/14 Vue.js
解决Mysql的left join无效及使用的注意事项说明
2021/07/01 MySQL