文档章节

关于深度 clone 的后续讨论

zTree
 zTree
发布于 2012/11/23 17:00
字数 829
阅读 540
收藏 2

在 zTree v3.5 发布之前看到了 [愚人码头] 的一篇文章《JavaScript深度克隆(深度拷贝)一个对象》,觉得 zTree 中的 clone 方法是应该适当优化一下,看着优化后的代码的确很简洁,大概测试无误,简单修正一下后,就直接拿了过来。

后来想了想,其实有时候代码也不能绝对为了优雅而忽略了性能,所以今天做了个简单的性能测试。

在测试过程中发现新代码虽然优雅,但效率却要略低于原先的代码,这让我很诧异,经过分析原来是

if(obj.hasOwnProperty(i)){...}
这个判断在作怪,每个属性在复制前都要判断一下,自然影响了效率。而且这句话还会产生另一个隐患——对于继承出来的对象在 clone 时会导致继承的属性全部被丢掉了。(对比了一下 jQuery 的extend 方法,clone 对象后是不会丢掉继承的属性的) 所以 果断删除这一句,删除后,效率与原先代码没有什么差异了。( 这个修正会在 v3.5.01 中一起发布的,对于 zTree 的节点数据来说应该是不会有这方面影响的

同时,对于有些朋友推崇的最精简的方法做了性能比较(这里暂不讨论这个方法有其他一些隐患以及兼容方面的问题)

JSON.parse(JSON.stringify(obj))
真的很简练的方法,但是他的效率只能达到咱们自己写的clone 方法的 一半;其实原因也很明显,先要遍历一遍 JSON 对象,把它转为 string;然后再把 string 转为 JSON 对象,同样的工作做了两遍,自然效率减半了。

我并不想强调你一定要用哪种方法,具体问题还是需要具体分析,只是想说明大家再决定采用什么方法的时候,还是要多考虑一些因素:代码的优雅、效率、兼容性 等等,选择适合自己的方法就可以了。

完整代码如下:

<!DOCTYPE HTML>
<html>
  <head>
    <title>CLONE TEST</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<script type="text/javascript">
		//zTree 原先的 clone 方法
		function cloneOld (jsonObj) {
			var buf;
			if (jsonObj instanceof Array) {
				buf = [];
				var i = jsonObj.length;
				while (i--) {
					buf[i] = arguments.callee(jsonObj[i]);
				}
				return buf;
			}else if (typeof jsonObj == "function"){
				return jsonObj;
			}else if (jsonObj instanceof Object){
				buf = {};
				for (var k in jsonObj) {
					buf[k] = arguments.callee(jsonObj[k]);
				}
				return buf;
			}else{
				return jsonObj;
			}
		}
		//zTree 使用更简洁的 clone 方法
		function cloneNew (obj) {
			if (obj === null) return null;
			var o = obj.constructor === Array ? [] : {};
			for(var i in obj){
				//测试中可以打开 if 语句,看看效率的变化
//				if(obj.hasOwnProperty(i)){
					o[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === "object" ? arguments.callee(obj[i]) : obj[i]);
//				}
			}
			return o;
		}
		//最精简的 clone 方法
		function cloneSimple (obj) {
			return JSON.parse(JSON.stringify(obj));
		}
		//测试方法
		function testClone(clone) {
			var i, times = 1000, start = new Date();
			for (i=0; i<times; i++) {
				clone(testCase);
			}
			var end = new Date();
			console.log(clone.name + " use " + (end.getTime() - start.getTime()));
		}

		var testCase = [], curId=1, maxLevel=3, num=4;
		//初始化测试数据
		function makeCase (list, level) {
			var i;
			for (i=0; i<num; i++) {
				var obj = {
					id : curId,
					level : level,
					name : "testItem_" + curId,
					title : "test Title " + curId
				};
				curId++;
				if (level < maxLevel) {
					obj.children = [];
					makeCase(obj.children, level+1);
				}
				list.push(obj);
			}
		}
		makeCase(testCase, 1);
	</script>
  </head>
  <body>
	  <button type="button" onclick="testClone(cloneOld)">Test Clone Old</button>
	  <button type="button" onclick="testClone(cloneNew)">Test Clone New</button>
	  <button type="button" onclick="testClone(cloneSimple)">Test Clone Simple</button>
  </body>
</html>

© 著作权归作者所有

zTree

zTree

粉丝 859
博文 21
码字总数 21754
作品 1
朝阳
技术主管
私信 提问
加载中

评论(1)

何川丰
何川丰
写的不错,支持。
Linux Namespace和Cgroup

为了方便阅读,将自己写的所有关于namespace和cgroup的文章统一列在这里,希望对有需要的人有所帮助,后续有新的内容后将会更新这里的列表。 namespace 包含了Linux目前常用的6个namespace的...

wuyangchun
2019/09/29
0
0
深拷贝的终极探索(99%的人都不知道)

划重点,这是一道面试必考题,我靠这道题刷掉了多少面试者✧(≖ ◡ ≖✿)嘿嘿 首先这是一道非常棒的面试题,可以考察面试者的很多方面,比如基本功,代码能力,逻辑能力,而且进可攻,退可守...

颜海镜
2018/10/13
0
0
Java设计模式百例(番外) - Java的clone

本文源码见:https://github.com/get-set/get-designpatterns/tree/master/prototype 本文是为下一篇“Java设计模式百例 - 原型模式”做铺垫,讨论一下Java中的对象克隆。本文内容综合了《E...

享学IT
2017/11/17
0
0
JAVA中深拷贝与浅拷贝(在网上找到的) 希望对于理解深拷贝与浅拷贝有帮助

原文:http://www.cnblogs.com/afirefly/archive/2010/09/08/1821810.html 什么是clone? 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时...

not_in_mountain
2017/09/29
0
0
看完这篇还不清楚Netty的内存管理,那我就哭了!

说明 在学习Netty的时候,ByteBuf随处可见,但是如何高效分配ByteBuf还是很复杂的,Netty的池化内存分配这块还是比较难的,很多人学习过,看过但是还是云里雾里的,本篇文章就是主要来讲解:...

匠心零度
2019/08/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 现在看动弹的人都是什么状态

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《夏日、教室与望着窗外的我》- Candy_Wind 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
68
1
wamp环境安装redis扩展

1.查看phpinfo信息根据配置信息下载对应的扩展 关键信息:VC14,TS,x86 2.下载php_redis和php_igbinary扩展 php_redis扩展下载地址: https://windows.php.net/downloads/pecl/snaps/redis...

点滴课程
今天
36
0
开源商城开发笔记1-创建MyBatis示例

一、修改pom.xml,引入MyBatis,JUnit,Log4j <dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.4</version>......

土龙
今天
56
0
The Best Way To Learn English in 2020 (In my humble opinion.)

✅Here is the plan: THINGS YOU WILL NEED: - 1 hour per day (30 minutes will work as well). - a notebook and a pen to write down new vocabulary each day. - an English song. - an ......

FalconChen
昨天
73
0
nodejs 使用 pako 压缩数据

github https://github.com/nodeca/pako 应用场景 大对象传输一般使用json, 在worker或local storage中还必须使用字符串, pako可以对字符串或者 Uint8Array 数据进行压缩和解压, 牺牲一部分读...

阿豪boy
昨天
79
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部