其实,看不懂的并不是JavaScript程序,而是lambda表达式!JavaScript虽然“卑微”,却有着“高贵”的理论背景——lambda演算,这是一个需要深入研究的领域,此处按下不表。
最近读了很多关于JavaScript的资料,有一个词频频出现:Unobtrusive Scripting。查字典,obtrude = force (oneself, one's opinions, ideas, etc) upon sb/sth, esp when unwanted. 所以,Unobtrusive可以解释为“不强加于人的,优雅的,温和的,君子的”。那么,为什么现在会强调Unobtrusive Scripting呢?
1、内容的可访问性(Web Content Accessibility)
HTML Elements的行为表示为鼠标/键盘事件,但很少有Scripters会考虑用户没有鼠标的情况。W3C发布了一个Web Content Accessibility Guidelines,建议使用不依赖于设备的事件处理程序,如果必须使用依赖于设备的处理程序的话,尽量提供冗余的输入机制,如同时支持鼠标和键盘("onmousedown"与"onkeydown","onmouseup“与"onkeyup","onclick"与"onkeypress"等)。

--------------------------------------------------------------------------------------------------------------------------------------、

JAVASCRIPT程序优化
如图为某信息系统的权限设置模块之用户界面:

如何获取用户的功能权限和对象权限的设置信息,还是大有讲究的。下面的代码列表1为未优化的JavaScript代码:
JavaScript Code List 1:
// non-optimized version
var functorList = new StringBuilder();
var objectList = new StringBuilder();
var coll = document.getElementsByTagName("INPUT");
// one pass scan to traverse the nodes collection coll to build functorList
for (var i = 0; i < coll.length; i++)
{
 var _obj = coll[i];
 if (_obj.type != "checkbox") continue;
 
 if (_obj.id.indexOf("functor_") >= 0 && _obj.checked == true)
 {
  var id = _obj.id;
  id = id.substring("functor_".length, id.length);
  functorList.append(id + ";");
 }
}
// multi-pass scan to build objectList
for (var i = 0; i < coll.length; i++)
{
 var _obj = coll[i];
 if (_obj.type == "checkbox" && _obj.id.indexOf("object_") >= 0)
 {
  if (_obj.id.indexOf("_parent") > 0 || _obj.id.indexOf("_child") > 0) continue;
  if (_obj.id.indexOf("_r") > 0 || _obj.id.indexOf("_a") > 0 || _obj.id.indexOf("_m") > 0 || _obj.id.indexOf("_d") > 0) continue;
var pid = _obj.id;
  var gid = pid.replace(/object_/g, "");
  var orList = new StringBuilder();
  orList.append(gid + ":");
  
  for (var k = 0; k < coll.length; k++)
  {
   var _objK = coll[k];
   if (_objK.type == "checkbox" && _objK.id == pid + "_r" && _objK.checked)
   {
    for (var r = 0; r < coll.length; r++)
    {
     var _objR = coll[r];
     if (_objR.type == "radio" && _objR.getAttribute("name") == "radio_" + gid + "_r" && _objR.checked)
     {
      orList.append("r_" + _objR.value + ":");
      break;
     }
    }
   }
   else if (_objK.type == "checkbox" && _objK.id == pid + "_a" & _objK.checked)
   {
    orList.append("a_" + ":");
   }
   else if (_objK.type == "checkbox" && _objK.id == pid + "_m" && _objK.checked)
   {
    for (var m = 0; m < coll.length; m++)
    {
     var _objM = coll[m];
     if (_objM.type == "radio" && _objM.getAttribute("name") == "radio_" + gid + "_m" && _objM.checked)
     {
      orList.append("m_" + _objM.value + ":");
      break;
     }
    }
   }
   else if (_objK.type == "checkbox" && _objK.id == pid + "_d" && _objK.checked)
   {
    for (var d = 0; d < coll.length; d++)
    {
     var _objD = coll[d];
     if (_objD.type == "radio" && _objD.getAttribute("name") == "radio_" + gid + "_d" && _objD.checked)
     {
      orList.append("d_" + _objD.value + ":");
      break;
     }
    }
   }
  }
  objectList.append(orList.toString() + ";");
 }
}
JavaScript Code List 2是优化后的代码:
// optimized version
var functorListEx = new StringBuilder();
var objectListEx = new StringBuilder();
var coll = document.getElementsByTagName("INPUT");
// regular expression for matching
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;
// 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();
// one pass scan to traverse the nodes collection (coll) to build functorListEx
// and intermediate arrays
for (var i = 0; i < coll.length; i++)
{
 var _obj = coll[i];
 if (_obj.type != "checkbox" && _obj.type != "radio") continue;
 var _match;
 
 if (_obj.checked && (_match = _obj.id.match(fnRE)) != null)
 {
  functorListEx.append(_match[0].split("_")[1] + ";");
 }
 else if (_obj.checked && (_match = _obj.name.match(objRE_r)) != null)
 {
  aryRList[_match[0].split("_")[1]] = "r_" + _obj.value;
 }
 else if (_obj.checked && (_match = _obj.id.match(objRE_a)) != null)
 {
  aryAList[_match[0].split("_")[1]] = "a_";
 }
 else if (_obj.checked && (_match = _obj.name.match(objRE_m)) != null)
 {
  aryMList[_match[0].split("_")[1]] = "m_" + _obj.value;
 }
 else if (_obj.checked && (_match = _obj.name.match(objRE_d)) != null)
 {
  aryDList[_match[0].split("_")[1]] = "d_" + obj.value;
 }
 else if (_obj.checked && (_match = _obj.id.match(objRE)) != null)
 {
  aryObjList.push(_match[0].split("_")[1]);
 }
}
// further process to build objectListEx from the intermediate arrays
for (var i = 0; i < aryObjList.length; i++)
{
 var _id = aryObjList[i];
 var _r = aryRList[_id] == null ? "" : aryRList[_id];
 var _a = aryAList[_id] == null ? "" : aryAList[_id];
 var _m = aryMList[_id] == null ? "" : aryMList[_id];
 var _d = aryDList[_id] == null ? "" : aryDList[_id];
 objectListEx.append(_id + ":" + _r + ":" + _a + ":" + _m + ":" + _d + ";");
}
====================================================================================
今天收到《程序员》第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学习笔记 及 JAVAScript优化相关推荐

  1. Javascript学习笔记3 Javascript与BOM简介

    什么是BOM BOM是browser object model的缩写,简称浏览器对象模型 BOM提供了独立于内容而与浏览器窗口进行交互的对象 由于BOM主要用于管理窗口与窗口之间的通讯,因此其核心对象 ...

  2. JavaScript学习笔记(2)——JavaScript和DOM的关系

    文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口.DOM实际上是以面向对象方式描述的文档模型.DOM定义了表示和修改文档所需的 ...

  3. JavaScript 学习笔记 - 12 JavaScript 应用示例

    目录 12.1 使用可折叠菜单 12.2 添加下拉菜单 12.3 改进下拉菜单 12.4 带说明的幻灯片 12.5 一个娱乐姓名生成器 12.6 柱状图生成器 12.7 样式表切换器 12.1 使用可 ...

  4. JavaScript学习笔记2——JavaScript操作BOM对象

    BOM模型 BOM:浏览器对象模型(Browser Object Model) BOM提供了独立于内容的.可以与浏览器窗口进行互动的对象结构 BOM可实现功能 弹出新的浏览器窗口 移动.关闭浏览器窗口 ...

  5. JavaScript学习笔记(8)——JavaScript语法之运算符

    一. 算术运算符: 运算符 描述 例子 结果 + 加 x=y+2 x=7 - 减 x=y-2 x=3 * 乘 x=y*2 x=10 / 除 x=y/2 x=2.5 % 求余数 (保留整数) x=y%2 ...

  6. JavaScript学习笔记:JavaScript获取元素:id,标签名,类名,querySelector,querySelectorall,获取body,html

    1.根据ID获取元素 ● 语法:document.getElementById(id) ● 作用:根据ID获取元素对象 ● 参数:id值,区分大小写的字符串 ● 返回值:元素对象 或 null 案例代 ...

  7. JavaScript学习笔记(五)---cookie、Proxy、服务器、PHP语言、http协议、同步异步、事件轮循机制、ajax编写、接口

    JavaScript学习笔记(五)---cookie.Proxy.服务器.PHP语言.http协议.同步异步.事件轮循机制.ajax编写.接口 1.cookie 1.1cookie概念 1.2cook ...

  8. Java程序猿的JavaScript学习笔记(12——jQuery-扩展选择器)

    计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...

  9. Java程序猿的JavaScript学习笔记(汇总文件夹)

    最终完结了,历时半个月. 内容包含: JavaScript面向对象特性分析,JavaScript高手必经之路. jQuery源代码级解析. jQuery EasyUI源代码级解析. Java程序猿的J ...

  10. JavaScript学习笔记(五)

    JavaScript学习笔记(五) ①Array类 本地对象 ②Date类 ①Global对象 对象的类型   内置对象 ②Math对象 宿主对象 今天继续学习JS中的对象,昨天内置对象Global对 ...

最新文章

  1. F#探险之旅(四):面向对象编程(中)
  2. 微软推出 Pylance,改善 VS Code 中的 Python 体验
  3. Win10 64位 汇编环境的搭建: 安装配置 DOSBOX、MASM
  4. [sybase]自动增长字段创建方法
  5. C# 自定义配置文件
  6. 腾讯广告算法大赛 | 复赛第二周最佳进步奖得主心得分享
  7. linux 查看设备 usb设备驱动程序,Linux USB设备驱动程序未被探测
  8. linux打开gaussian16软件,Gaussian View 在Ubuntu16下的安装
  9. weex的组件 web的使用(结合webview模块)
  10. 2019CCPCQHD Angle Beats
  11. java实现华氏温度和摄氏温度互相转换
  12. 量化投资学习必读书目(十五)-《现代投资组合理论与投资分析》
  13. 码蹄集 - MT2095 · 曲径折跃
  14. 一些适合程序员玩的游戏
  15. 安卓盒子装mysql_小白学mysql第一天:mysql安装
  16. STM32L0 内部EEPROM写读
  17. String类常用方法思维导图总结
  18. 深度:华为芯片的自研之旅
  19. 两步轻松搞定 编辑器上传图片尺寸过大 超出前台显示区域问题!
  20. 鲈鱼优化算法(Matlab代码实现)

热门文章

  1. android mat教程,OpenCV for Android - Access elements of Mat
  2. java多线程实现医院叫号_Java多线程经典题目(医院挂号)
  3. mysql --force 无效_【技能库】--mysql 索引失效 force index也失效-- 原因解决方案(256)...
  4. php查询mysql增加模板消息_php 实现发送微信模板消息
  5. ocr tesseract_OCR引擎之战— Tesseract与Google Vision
  6. 报错Could not resolve resource location pattern [classpath:com/yh/mapping/*.xml]
  7. 计算机的使用知识,计算机基础知识计算机的使用方法
  8. linux mint 引导类型,LinuxMint18配置Grub2默认启动操作系统
  9. dz论坛自定义html,关于diy模块中的自定义html
  10. mysql双主日志_MySQL双主双从配置开启二进制日志