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

 更新时间:2016年12月29日 11:11:00   投稿:lqh  
这篇文章主要介绍了javascript中的深复制详解及实例分析的相关资料,需要的朋友可以参考下

 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的数值类型。下面我们先来看一个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延时加载之defer测试

    javascript延时加载之defer测试

    偶尔发现 js 中有个延时加载的标签 defer,还在疑惑这么好用的东西为什么没有流行起来,本人今天把它拾起来用了一下,发现只在ie7,8,9和360安全济览器下可以,知道为什么不用它了吧
    2012-12-12
  • 小程序使用watch监听数据变化的方法详解

    小程序使用watch监听数据变化的方法详解

    这篇文章主要介绍了小程序使用watch监听数据变化的方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • 微信小程序实现自定义底部导航

    微信小程序实现自定义底部导航

    这篇文章主要为大家详细介绍了微信小程序实现自定义底部导航,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • avalonjs实现仿微博的图片拖动特效

    avalonjs实现仿微博的图片拖动特效

    JavaScript实现仿微博的图片拖动特效,貌似这些天有不少朋友需要这功能,今天发现这款是js制作的好,不敢独享,希望需要的朋友喜欢哦。
    2015-05-05
  • javascript数据结构与算法之检索算法

    javascript数据结构与算法之检索算法

    查找数据有2种方式,顺序查找和二分查找。顺序查找适用于元素随机排列的列表。二分查找适用于元素已排序的列表。二分查找效率更高,但是必须是已经排好序的列表元素集合
    2015-04-04
  • JavaScript 格式化数字、金额、千分位、保留几位小数、舍入舍去

    JavaScript 格式化数字、金额、千分位、保留几位小数、舍入舍去

    这篇文章主要介绍了JavaScript 格式化数字、金额、千分位、保留几位小数、舍入舍去,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • TypeScript如何开启严格空值检查

    TypeScript如何开启严格空值检查

    这篇文章主要介绍了TypeScript如何开启严格空值检查,文章围绕TypeScript的相关资料展开详情内容,需要的小伙伴可以参考一下
    2022-03-03
  • 微信小程序日期时间选择器使用方法

    微信小程序日期时间选择器使用方法

    这篇文章主要为大家详细介绍了微信小程序日期时间选择器的使用方法,自定义精确到分秒或时段,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 使用Echart实现绘制立体的柱状图

    使用Echart实现绘制立体的柱状图

    EChart开源来自百度商业前端数据可视化团队,基于html5 Canvas,是一个纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。本文将利用EChart绘制立体的柱状图,感兴趣的可以学习一下
    2022-03-03
  • JavaScript原生开发视频播放器的实现代码

    JavaScript原生开发视频播放器的实现代码

    这篇文章我们将一起探索一份自定义的视频播放器实现代码,甚至还可以实现有弹幕功能,文中的示例代码讲解详细,感兴趣的可以了解一下
    2023-06-06

最新评论