龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > Javascript编程 >

编写高质量JavaScript代码的基本要点(1)(3)

时间:2013-03-06 14:58来源:未知 作者:admin 点击:
分享到:
for循环(for Loops) 在for循环中,你可以循环取得数组或是数组类似对象的值,譬如arguments和HTMLCollection对象。通常的循环形式如下: //次佳的循环 for ( var i

for循环(for Loops)

在for循环中,你可以循环取得数组或是数组类似对象的值,譬如arguments和HTMLCollection对象。通常的循环形式如下:

  1. // 次佳的循环  
  2. for (var i = 0; i < myarray.length; i++) {  
  3.    // 使用myarray[i]做点什么  

这种形式的循环的不足在于每次循环的时候数组的长度都要去获取下。这回降低你的代码,尤其当myarray不是数组,而是一个HTMLCollection对象的时候。

HTMLCollections指的是DOM方法返回的对象,例如:

  1. document.getElementsByName()  
  2. document.getElementsByClassName()  
  3. document.getElementsByTagName() 

还有其他一些HTMLCollections,这些是在DOM标准之前引进并且现在还在使用的。有:

  1. document.images: 页面上所有的图片元素  
  2. document.links : 所有a标签元素  
  3. document.forms : 所有表单  
  4. document.forms[0].elements : 页面上第一个表单中的所有域 

集合的麻烦在于它们实时查询基本文档(HTML页面)。这意味着每次你访问任何集合的长度,你要实时查询DOM,而DOM操作一般都是比较昂贵的。

这就是为什么当你循环获取值时,缓存数组(或集合)的长度是比较好的形式,正如下面代码显示的:

  1. for (var i = 0, max = myarray.length; i < max; i++) {  
  2.    // 使用myarray[i]做点什么  

这样,在这个循环过程中,你只检索了一次长度值。

在所有浏览器下,循环获取内容时缓存HTMLCollections的长度是更快的,2倍(Safari3)到190倍(IE7)之间。//zxx:此数据貌似很老,仅供参考

注意到,当你明确想要修改循环中的集合的时候(例如,添加更多的DOM元素),你可能更喜欢长度更新而不是常量。

伴随着单var形式,你可以把变量从循环中提出来,就像下面这样:

  1. function looper() {  
  2.    var i = 0,  
  3.         max,  
  4.         myarray = [];  
  5.    // ...  
  6.    for (i = 0, max = myarray.length; i < max; i++) {  
  7.       // 使用myarray[i]做点什么  
  8.    }  

这种形式具有一致性的好处,因为你坚持了单一var形式。不足在于当重构代码的时候,复制和粘贴整个循环有点困难。例如,你从一个函数复制了一个循环到另一个函数,你不得不去确定你能够把i和max引入新的函数(如果在这里没有用的话,很有可能你要从原函数中把它们删掉)。

最后一个需要对循环进行调整的是使用下面表达式之一来替换i++。

  1. ii = i + 1  
  2. i += 1 

JSLint提示您这样做,原因是++和–-促进了“过分棘手(excessive trickiness)”。//zxx:这里比较难翻译,我想本意应该是让代码变得更加的棘手

如果你直接无视它,JSLint的plusplus选项会是false(默认是default)。

还有两种变化的形式,其又有了些微改进,因为:

◆ 少了一个变量(无max)

◆ 向下数到0,通常更快,因为和0做比较要比和数组长度或是其他不是0的东西作比较更有效率

  1. //第一种变化的形式:  
  2.  
  3. var i, myarray = [];  
  4. for (i = myarray.length; i–-;) {  
  5.    // 使用myarray[i]做点什么  
  6. }  
  7.  
  8. //第二种使用while循环:  
  9.  
  10. var myarray = [],  
  11.     i = myarray.length;  
  12. while (i–-) {  
  13.    // 使用myarray[i]做点什么  

这些小的改进只体现在性能上,此外JSLint会对使用i–-加以抱怨。

for-in循环(for-in Loops)

for-in循环应该用在非数组对象的遍历上,使用for-in进行循环也被称为“枚举”。

从技术上将,你可以使用for-in循环数组(因为JavaScript中数组也是对象),但这是不推荐的。因为如果数组对象已被自定义的功能增强,就可能发生逻辑错误。另外,在for-in中,属性列表的顺序(序列)是不能保证的。所以最好数组使用正常的for循环,对象使用for-in循环。

有个很重要的hasOwnProperty()方法,当遍历对象属性的时候可以过滤掉从原型链上下来的属性。

思考下面一段代码:

  1. // 对象  
  2. var man = {  
  3.    hands: 2,  
  4.    legs: 2,  
  5.    heads: 1  
  6. };  
  7.  
  8. // 在代码的某个地方  
  9. // 一个方法添加给了所有对象  
  10. if (typeof Object.prototype.clone === "undefined") {  
  11.    Object.prototype.clone = function () {};  

在这个例子中,我们有一个使用对象字面量定义的名叫man的对象。在man定义完成后的某个地方,在对象原型上增加了一个很有用的名叫 clone()的方法。此原型链是实时的,这就意味着所有的对象自动可以访问新的方法。为了避免枚举man的时候出现clone()方法,你需要应用hasOwnProperty()方法过滤原型属性。如果不做过滤,会导致clone()函数显示出来,在大多数情况下这是不希望出现的。

  1. // 1.  
  2. // for-in 循环  
  3. for (var i in man) {  
  4.    if (man.hasOwnProperty(i)) { // 过滤  
  5.       console.log(i, ":", man[i]);  
  6.    }  
  7. }  
  8. /* 控制台显示结果  
  9. hands : 2  
  10. legs : 2  
  11. heads : 1  
  12. */  
  13. // 2.  
  14. // 反面例子:  
  15. // for-in loop without checking hasOwnProperty()  
  16. for (var i in man) {  
  17.    console.log(i, ":", man[i]);  
  18. }  
  19. /*  
  20. 控制台显示结果  
  21. hands : 2  
  22. legs : 2  
  23. heads : 1  
  24. clone: function()  
  25. */ 

另外一种使用hasOwnProperty()的形式是取消Object.prototype上的方法。像是:

  1. for (var i in man) {  
  2.    if (Object.prototype.hasOwnProperty.call(man, i)) { // 过滤  
  3.       console.log(i, ":", man[i]);  
  4.    }  

其好处在于在man对象重新定义hasOwnProperty情况下避免命名冲突。也避免了长属性查找对象的所有方法,你可以使用局部变量“缓存”它。

  1. var i, hasOwn = Object.prototype.hasOwnProperty;  
  2. for (i in man) {  
  3.     if (hasOwn.call(man, i)) { // 过滤  
  4.         console.log(i, ":", man[i]);  
  5.     }  

严格来说,不使用hasOwnProperty()并不是一个错误。根据任务以及你对代码的自信程度,你可以跳过它以提高些许的循环速度。但是当你对当前对象内容(和其原型链)不确定的时候,添加hasOwnProperty()更加保险些。格式化的变化(通不过JSLint)会直接忽略掉花括号,把if语句放到同一行上。其优点在于循环语句读起来就像一个完整的想法(每个元素都有一个自己的属性”X”,使用”X”干点什么):

  1. // 警告: 通不过JSLint检测  
  2. var i, hasOwn = Object.prototype.hasOwnProperty;  
  3. for (i in man) if (hasOwn.call(man, i)) { // 过滤  
  4.     console.log(i, ":", man[i]);  

精彩图集

赞助商链接