文档章节

关于深度 clone 的后续讨论

zTree
 zTree
发布于 2012/11/23 17:00
字数 829
阅读 214
收藏 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

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

评论(1)

何川丰
何川丰
写的不错,支持。
深拷贝的终极探索(99%的人都不知道)

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

颜海镜
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
【Git 第12课】 抓取/推送数据

当添加了远程仓库之后,肯定不能只在列表中看到个名字就完事了。我们要通过远程仓库来存放数据。 抓取数据的命令是: git fetch [remote-name] 比如对于我们上次添加的 myremote 远程仓库,就...

Harry_sir
2016/01/02
24
0
关于Java对象深度Clone以及序列化与反序列化的使用

我们可以利用clone方法来实现对象只见的复制,但对于比较复杂的对象(比如对象中包含其他对象,其他对象又包含别的对象.....)这样我们必须进行层层深度clone,每个对象需要实现 cloneable接...

binhu
2016/03/29
46
0

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 自定义你的空间

通过对你的空间进行界面的自定义能够让你的空间更加出类拔萃。 如果你具有空间管理员权限,你可以修改你空间的颜色配色,添加你自己的空间标识,选择是否在你空间中显示边栏。或者你可以进入...

honeymose
18分钟前
0
0
Ubuntu18.04 安装MySQL

1.安装MySQL sudo apt-get install mysql-server 2.配置MySQL sudo mysql_secure_installation 3.设置MySQL非root用户 设置原因:配置过程为系统root权限,在构建MySQL连接时出现错误:ERROR...

AI_SKI
今天
3
0
3.6 rc脚本(start方法) 3.7 rc脚本(stop和status方法) 3.8 rc脚本(以daemon方式启动)

3.6-3.7 rc脚本(start、stop和status方法) #!/usr/bin/env python# -*- coding: utf-8 -*-# [@Version](https://my.oschina.net/u/931210) : python 2.7# [@Time](https://my.oschina.......

隐匿的蚂蚁
今天
3
0
Cnn学习相关博客

CNN卷积神经网络原理讲解+图片识别应用(附源码) 笨方法学习CNN图像识别系列 深度学习图像识别项目(中):Keras和卷积神经网络(CNN) 卷积神经网络模型部署到移动设备 使用CNN神经网络进行...

-九天-
昨天
5
0
flutter 底部输入框 聊天输入框 Flexible

想在页面底部放个输入框,结果键盘一直遮住了,原来是布局问题 Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("评论"), ...

大灰狼wow
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部