`
ruilin215
  • 浏览: 1108336 次
  • 性别: Icon_minigender_2
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

再议《JavaScript代码优化一例》

阅读更多

今天收到《程序员》第8期,读到杨建华先生的“JavaSctipt代码优化一例”。仔细读来,觉得所做优化未能尽彻。所以专写一篇文章来讨论杨先生的例子。原例可以在杨先生的blog上找到:
http://prowyh.spaces.live.com/blog/cns!EAAA8AB356F88EA0!403.entry

一、正则表达式的创建代码
---
这样的创建代码实在冗余:
var fnRE = /functor_[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}/i;
var objRE = /object_[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}$/i;
var objRE_r = /radio_[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}_r/i;
var objRE_a = /object_[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}_a/i;
var objRE_m = /radio_[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}_m/i;
var objRE_d = /radio_[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12}_d/i;

仔细读来,其实就是一个添加前后缀的GUID。那么可否写成如下:
var GUID = '([0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12})';
var fnRE = new RegExp('(functor_)'+ GUID, 'i');
var objRE = new RegExp('(object_)' + GUID + '$', 'i');
var objRE_r = new RegExp('(radio_)' + GUID + '_(r)', 'i');
var objRE_a = new RegExp('(object_)' + GUID + '_(a)', 'i');
var objRE_m = new RegExp('(radio_)' + GUID + '_(m)', 'i');
var objRE_d = new RegExp('(radio_)' + GUID + '_(d)', 'i');

这里看起来是用了字符串连接运算,但由于变量声明只运算一次,因此对效率没什么影响。而且可读性强了,修改起来也方便。
读注意这里用到了正则表达式中的分组'( )',这在后面是会很有用的。

二、正则使用中的分组
---
代码总是通过
aryAList[_match[0].split("_")[1]] = "a_";
这样的形式来从匹配中分离GUID,但如果使用上面的分组,那么这项运算就不必要了。简单的使用
aryAList[_match[2]] = "a_";
就可以得到结果。

三、应注意DOM引用的耗时
---
代码中,在循环内不断地访问DOM对象的成员,然而DOM对象的成员存取是耗时的。更细的说,每一个成员
都会通过COM组件封装,因此效率是差的。所以下面的代码:
else if ((_match = _obj.name.match(objRE_m)) != null) {
}
else if ((_match = _obj.name.match(objRE_d)) != null) {
}
应当被改作:
var name = _obj.name;
else if ((_match = name.match(objRE_m)) != null) {
}
else if ((_match = name.match(objRE_d)) != null) {
}

四、过于复杂的逻辑
---
代码过于依赖其它语言的编程经验,而忽略了JavaScript的自身特性。因此实现的逻辑中规中矩,但是难以
扩展,而且复杂。例如循环中的大量if..else if ...连用。后文单独给出这部分的优化。

五、从StringBuilder()接口来看,优化程度不够
---
文章提到StringBuilder是一个字符串构建的高效对象。我留意到它的使用是:
objectListEx.append(_id + ":" + _r + ":" + _a + ":" + _m + ":" + _d + ";");
那么可以说这个对象的优化是不够的。因为这里传入一个字符串参数,而传入参数又用字符串连接运算,
效率提升很有限。
如果StringBuilder是用array.join来实现字符串拼接的话,那么更加良好的方式是允许在append中使用多
个参数。例如:
objectListEx.append = function() {
this.push.apply(this, arguments);
}
objectListEx.toString = function() {
return this.join('');
}
那么,上例的添加就可以写成:
objectListEx.append(_id , ":" , _r , ":" , _a , ":" , _m , ":" , _d , ";");
这就避免了多余的字符串连接运算。

六、新的优化后版本
---
// optimized version
var functorListEx = new StringBuilder();
var objectListEx = new StringBuilder();

var coll = document.getElementsByTagName("INPUT");

// regular expression for matching
var GUID = '([0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{12})';
var fnRE = new RegExp('(functor_)'+ GUID, 'i');
var objRE = new RegExp('(object_)' + GUID + '$', 'i');
var objRE_r = new RegExp('(radio_)' + GUID + '_(r)', 'i');
var objRE_a = new RegExp('(object_)' + GUID + '_(a)', 'i');
var objRE_m = new RegExp('(radio_)' + GUID + '_(m)', 'i');
var objRE_d = new RegExp('(radio_)' + GUID + '_(d)', 'i');

// helper data structures used by optimized algorithm
var aryObjList = new Array();
var aryRList = new Array();
var aryAList = new Array();
var aryMList = new Array();
var aryDList = new Array();

var aryList = {
r: aryRList,
a: aryAList,
m: aryMList,
d: aryDList
}

// one pass scan to traverse the nodes collection (coll) to build functorListEx
// and intermediate arrays
for (var i=0,imax=coll.length; i<imax; i++) {
var _obj = coll[i];
if (!_obj.checked) continue; // <-- 更快的检测
if (_obj.type != "checkbox" && _obj.type != "radio") continue;

var id = _obj.id, name = _obj.name;
var _match = id.match(fnRE) || name.match(objRE_r) || id.match(objRE_a) ||
name.match(objRE_m) || name.match(objRE_d) || id.match(objRE);

if (!_match) continue;

var tag = _match[3], tag2 = tag+'_', guid = _match[2];
switch (tag) {
'a': aryList[tag][guid] = tag2; break;

'r', 'm', 'd':
aryList[tag][guid] = tag2 + _obj.value; break;

default :
if (_match[1]=='functor_') {
functorListEx.append(guid, ";")
}
else { // for _match[1]=='object_'
aryObjList.push(guid)
}
}
}

// further process to build objectListEx from the intermediate arrays
for (var i=0, imax=aryObjList.length; i<imax; i++) {
var id = aryObjList[i];
var r = aryRList[id] || "";
var a = aryAList[id] || "";
var m = aryMList[id] || "";
var d = aryDList[id] || "";

objectListEx.append(id , ":" , r , ":" , a , ":" , m , ":" , d , ";");
}

七、又一处小的优化
---
刚才想了想,其实上面代码中的switch还是啰嗦了。下面做一下下小的优化:
switch (_match[1] + tag) {
'functor_undefined': functorListEx.append(guid, ";"); break;

'object_undefined': aryObjList.push(guid); break;

'object_a': aryList[tag][guid] =tag2; break;

default: // for r,m,d
aryList[tag][guid] =tag2+ _obj.value;
}

分享到:
评论

相关推荐

    JavaScript代码优化一例.pdf

    JavaScript代码优化一例.pdf

    JAVA上百实例源码以及开源项目源代码

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    Java源码包100个设计实例.zip

    J2ME优化压缩PNG文件.rar J2ME冒险游戏CASPER源代码.rar J2me月光战机游戏源码.rar J2ME黑白棋游戏手机版 v2.1完整源码.rar JasperReports 报表类库v3.5.rar Java 3DMenu 界面源码.rar Java 3D魔方游戏源码及中文...

    javascript for循环从入门到偏门(效率优化+奇特用法)

    一,for循环的基本写法 代码如下: 代码如下: //例一for(var i=1;i&lt;=10;i++) { alert&#40;i&#41;; } 这段代码太简单了,我都不好意思拿出手。代码的执行结果是依次弹出1到10,PS:在早期的IE如IE6中,你把10改成...

    JAVA上百实例源码以及开源项目

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    java源码包---java 源码 大量 实例

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    Javascript中valueOf与toString区别浅析

    先看一例: 代码如下:var aaa = { i: 10, valueOf: function() { return this.i+30; }, toString: function() { return this.valueOf()+10; } } alert&#40;aaa &gt; 20&#41;; // true alert&#40;+aaa&#41;; // 40 ...

    java源码包2

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    asp.net知识库

    优化后的通用分页存储过程 sql语句 一些Select检索高级用法 SQL server 2005中新增的排序函数及应用 根据基本表结构及其数据生成 INSERT ... 的 SQL 简便的MS SQL 数据库 表内容 脚本 生成器 将表数据生成SQL脚本的...

    java源码包3

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    java源码包4

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    JAVA+JSP的聊天室 8个目标文件 简单 JavaScript万年历 显示出当前时间及年份,还可以选择年份及月份和日期 Java编写的HTML浏览器 一个目标文件 摘要:Java源码,网络相关,浏览器 Java编写的HTML浏览器源代码,一个很...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    JAVA+JSP的聊天室 8个目标文件 简单 JavaScript万年历 显示出当前时间及年份,还可以选择年份及月份和日期 Java编写的HTML浏览器 一个目标文件 摘要:Java源码,网络相关,浏览器 Java编写的HTML浏览器源代码,一个很...

    catom:JS库中的0运行时CSS

    您的javascript代码具有对任何样式的0个引用,剩下的只是已编译的散列clasnames作为字符串。 它与框架无关,因为它发出纯CSS并仅保留类名 例 App.js中的某个位置 import { css } from "catom" ; const ...

    规则::crown:功能性WebGL

    完成此操作后, regl将获取此描述,然后将其编译为优化JavaScript代码。 例如,这是一个绘制三角形的简单regl程序: // Calling the regl module with no arguments creates a full screen canvas and// WebGL ...

    xheditor v1.0.0 rc2 build 100401

    Word:实现Word代码自动检测并清理,提供高效完美的Word代码过滤方案,生成代码最优化精简,但是却不丢失任何细节效果。 UBB:提供完美的UBB可视化编辑解决方案,在您获得安全高效代码存储的同时,又能享受可视化...

    log4Net详解(共2讲)

    5、了解ExtJs代码的混淆、加密与优化; 6、了解大型实际商业OA项目流程及实战如何使用Ext快速开而简单地开发单页面应用。 注:如果你也在思考下面的问题,那么也许本视频讲座就是你想要的: 1、试与jQuery一争...

    roadsafety-docs:道路安全文件

    它遵循完全相同的原则:DRY、测试、易于维护、可扩展性、优化和重构,仅举几例。 当然,文档有错误、错别字、难以阅读的教程等等。 综合道路安全信息系统 2.0。 源代码和文档托管在 github 上: 如果您想提交补丁,...

    400电话办理选号系统

    由于程序数据在100万以上,反复查询数据会加大服务器负载,以至强双核3.0G CPU、2G内存 为例,连续查询10次列表会导致mysqld.exe/mysqld-nt.exe进程占用CPU约 50%~90%。同时,列表经过反复的交叉,可实现约100万条...

Global site tag (gtag.js) - Google Analytics