提高JavaScript程序的鲁棒性

转自老田的博客提高Javascript程序的鲁棒性》Posted in 2009/07/10  02:17h. yongbin

我是学控制理论出身,一个控制系统的鲁棒性,确实是在做系统设计时需要着重注意的。什么是控制系统的鲁棒性?

所谓“鲁棒性”,是指控制系统在一定(结构,大小)的参数摄动下,维持某些性能的特性(摘自百度百科……汗)。

在软件设计和开发中,同样也要时刻考虑提高鲁棒性。那么如何提高JavaScript程序的鲁棒性呢?我认为,RIA的鲁棒性,一般来讲,主要跟js的代码规范性和DOM操作有关系。下面我总结几点开发中需要注意的地方,让页面跑不死、不报错。这些事情可能在实际开发中都是小事,但是对于提高软件整体的鲁棒性,是非常critical的!

1. 严禁使用全局变量

唉,这个我可是亲身体会并深受其害啊!话说,当时我修改一个页面,开发一段脚本,需要写cookie。我发现页面上以前有人引用了一个js文件,里面有setCookie函数,好啊,拿来用!结果这个cookie死活都写不对。检查了半天,才发现这个页面引用的另外一个js文件也有一个setCookie函数,函数的参数和刚才那个不一样,而我调用的估计是这个函数!应该是之前的两个同事在同一个页面上自己搞自己的,结果竟然函数重名,而这两个函数都是全局的!设想一下,加入两个人都在全局范围内搞一个var i = 0; 那岂不是更加疯掉。

这个故事得到的教训,首先当然是同一个team的开发者应该多兼容并包,团结协作。其次呢,页面的js较多的时候,一定要有一个好的层次,避免全局变量。避免全局变量的一个方式是namespace。例如创建一个这样的程序结构:

   1:  var my_project = {
   2:    dom : {
   3:      get : function() {},
   4:      make : function() {} // etc.
   5:    },
   6:    cookie : {
   7:      get : function() {},
   8:      set : function() {},
   9:      remove : function() {}
  10:    },
  11:   
  12:    util : {
  13:      // some project utilities
  14:    }
  15:  }

2. 多使用短路表达式

全局变量的部分说的有点多了,大概是因为老田我经历过那类痛苦吧。短路表达式就是&&和||,在这里用来提高鲁棒性。举两个例子,第一,要得到某div节点的第一个节点的nodeName:

   1:  var div = document.getElementById("div_id");
   2:  var node_name;
   3:  if (div && div.firstChild) { // 在用firstChild前,先判断div是否存在
   4:    node_name = div.firstChild.nodeName;
   5:  }

其次,用||来快速解决一些浏览器兼容性问题:

   1:  // 得到元素内文本的跨浏览器解决方案
   2:  var text = span.innerText || span.textContent || "";

再例,用||来设置默认值:

   1:  // 设置默认值
   2:  var my_attr = span.getAttribute("my_attr") || default_value;

3. 操作元素前,首先判断其存在

在第二条里面已经举过例子。再举一例:

   1:  var input = document.getElementsByName("input")[0];
   2:  if (input) {
   3:    target = input.value;
   4:  }

4. 良好的代码缩进和格式

Doug Crockford,《JavaScirpt: The Good Parts》的作者,在给Google做演讲的时候,详细分析了代码格式的重要性。比如:

   1:  return
   2:  {
   3:    name : span.nodeName,
   4:    value : span.innerHTML
   5:  }

写这种代码的人肯定是C出身。js里面,后果就是return nothing。js有语句的自动补全机制,return这一样,会自动在末尾加上分号,导致返回。如果不注意的话,程序出了问题,很难找到原因。所以一定要养成一个代码格式的好习惯,把左大括号和return啊,if啊,function()啊,写在一起。也就是:

   1:  return {
   2:    // something
   3:  }

5. 使用跨浏览器的代码

在对DOM进行读取和操作时,处处想着浏览器兼容性这件事,免得最后返工,自己给自己找麻烦。比如,只用document.getElementById;用nodeName,而不用tagName;不用getElementsByClassName等先进的选择器;不用applyElement, removeNode, swapNode等IE only的方法。

在浏览器兼容性方面,强烈推荐ppk的站点quirksmode.org。ppk此人对各个浏览器都进行了测试,工作十分扎实,是我们的榜样啊!

6. 变量尽早定义

JavaScript的变量作用域是所在的整个function,在写代码的时候,如果变量在想用的时候再定义,很容易变得难于管理。在开发逻辑比较复杂的程序时,非常容易混乱,甚至变量重名。

7. 小心NodeList

NodeList,也就是节点列表,是一个陷阱,他不是静态的,而是危险的动态结构,它会立即反映文档的变化。一个经典的死循环案例:

   1:  var lis = ul.getElementsByTagName("li");
   2:  for (var i = 0; i < lis.length; i++) {
   3:    ul.appendChild(lis[i].cloneNode(true));
   4:  }

上面的代码里,这些li的length不是固定的,而是随着DOM的变化而变化。这个错误我是经历过一次啊,不过不是死循环。还拿这个ul和li举例子吧,我想删掉某个ul下面的所有li,代码类似于下面的样子,大家看看有什么问题呢?

   1:  var lis = ul.getElemenetsByTagName("li");
   2:  for (var i = 0; i < lis.length; i++) {
   3:    ul.removeChild(lis[i]);
   4:  }

8. 使用===和!==

某些人可能会问,我用==用的挺好的啊,为什么要用===?那我要反问,既然===更加严谨,没有类型转换,而==充满陷阱,为什么不用===?没有自信吗?哦,那只能说明你的程序不稳定,鲁棒性不好了。

==会进行自动类型转换,Crockford称它为evil twins。其他的不说了,举几个例子:

   1:  alert(0 == '');  // true
   2:  alert(false == '0'); //true
   3:  alert('\r\n' == 0); // true

9. 不要用with

在设计JavaScript这门语言的时候,with本来是为一些操作提供快捷方式的,但是设计的不够好,可以说js里面没有with会更好。举一个使用with的例子:

   1:  with(element.style) {
   2:    position = "absolute";
   3:    left = "100px";
   4:    top = "100px";
   5:  }

首先with破坏了这门语言的变量作用域结构。在js里面,postion, left和top本来应该变成全局变量的。可能有些人说,这样正好,我可以通过with来控制变量作用域!想法不错,JavaScript 1.7也引入了let语句来做这件事。但是,with会产生无法预想的后果,举例:

   1:  var a = '';
   2:  var obj = {b: 'b'};
   3:  with(obj) {
   4:   a = b;
   5:  }
   6:  alert(a); // result: 'b'

这里的a又变成外部变量了!除了这种诡异的事情之外,with语句的执行速度相对来说是非常缓慢的。所以结论就是,想要提高程序的鲁棒性,就不要用with。

10. 不要用eval

eval可以把一段字符串当作js代码来执行。eval经常被一些新手拿来用,例如:

eval("value = obj." + key + ";");

其实他完全可以:

value = obj["key"];

eval执行的时候会启用js解释器来执行这一小片代码,速度会慢很多。除此之外,程序的可调试性、可维护性大大降低。类eval的语句还有:

   1:  window.setTimeout("var i = 0", 1000);
   2:  var sum = new Function("x", "y", "return x+y");
posted @ 2011-08-04 15:20  像阳光一样  阅读(773)  评论(0编辑  收藏  举报