1. 区分大小写
所有的函数和变量都是区分大小写的,包括JavaScript核心对象,如Array和Object。因此
function myFunction() { }
不同于
function MyFunction() { }
2. 单引号和双引号
在JavaScript中单引号和双引号没有特殊的区别。因为XHTML规范要求XHTML属性值必须使用双引号,所以JavaScript开发者一般都选择单引号。例如:
var html = ' <h2 class="a">A list!</h2> ' + ' <ol>' + ' <li class="a">Foo</li> ' + ' <li class="a">Bar</li> ' + '</ol> ';
3. 换行
无论使用单引号还是双引号来创建字符串,字符串都不能包含换行符,这样会带来解析错误。例如:
var html = ' <h2 class="a">A list!</h2> <ol> <li class="a">Foo</li> <li class="a">Bar</li> </ol> ';
可以通过反斜杠来转义换行符,但如果打算第三方压缩工具来压缩代码,则可能会带来问题:
var html = ' <h2 class="a">A list!</h2> \ <ol>\ <li class="a">Foo</li> \ <li class="a">Bar</li> \ </ol> ';
最后的方案是,使用字符串串接操作符(+)将多行字符串串接起来
var html = ' <h2 class="a">A list!</h2> ' + ' <ol>' + ' <li class="a">Foo</li> ' + ' <li class="a">Bar</li> ' + '</ol> ';
4. 匿名函数
匿名函数是一种在定义时不带名称的函数,匿名函数对于在DOM对象上注册事件侦听器或者将函数作为参数传递给其它方法时特别有用。例如:
先定义函数,再将它作为事件侦听器
function clicked() { alert('Linked to: ' + this.href); } var anchor = ADS.$('someId'); ADS.addEvent(anchor, 'click', clicked);
直接使用匿名函数作为事件侦听器
var anchor = ADS.$('someId'); addEvent(anchor, 'click', function () { alert('Linked to: 'this.href); });
5. 作用域解析和闭包
作用域是指对某一属性(变量)或方法(函数)具有访问权限的代码空间。在JavaScript中,作用域是在函数中进行维护的。如:
// 变量myVariable的作用域限制在myFunction中 function myFunction() { var myVariable = 'inside'; } // 如果在函数之外访问myVariable,结果将是无效的 function myFunction() { var myVariable = 'inside'; } myFunction(); alert(myVariable); // 执行上面的函数不会影响到外部作用域 function myFunction() { var myVariable = 'inside'; } // 定义变量 var myVariable = 'outside'; // 执行前面的函数 myFunction(); alert(myVariable); // 提示"outside" // 如果在myFunction内去掉var关键字,那么myVariable变量的作用域将会在myFunction的外部 // 因此会修改外部的变量 function myFunction() { // 没有使用 var 关键字 myVariable = 'inside'; } // 定义变量 var myVariable = 'outside'; // 执行前面的函数 myFunction(); alert(myVariable); // 提示 "inside"
闭包是与作用域相关的一个概念,它指的是内部函数即使在外部函数执行完成并终止以后,仍然可以访问其外部函数的属性。当引用一个变量或方法时,JavaScript会沿着由对象执行路径构成作用域链进行解析,查找变量最近定义的值,一旦找到,即使用这个值。
例如,如果要实现一个initAnchors()函数,为页面中的3个链接注册事件侦听器,3个链接的id分时anchor1、anchor2和anchor3,单击每个链接显示相应的id值:
ADS.addEvent(window, 'load', function(W3CEvent) { for (var i=1 ; i<=3 ; i++ ) { var anchor = document.getElementById('anchor' + i); ADS.addEvent(anchor,'click',function() { alert('My id is anchor' + i); }); } });
运行的结果是错的,单击每个链接都会显示相同的信息:My id is anchor4
原因是变量i的值实际上是在单击事件发生时才从作用域链中取得的。当单击事件发生时,initAnchors()函数已经执行完毕,所以变量i的值等于4。作用域链的示意图如下图所示:
如果要得到正确的结果,需要把事件侦听器的注册转移到一个独立的函数中,并通过该函数的参数传递适当的值:
function registerListener(anchor, i) { ADS.addEvent(anchor, 'click', function() { alert('My id is anchor' + i); }); } function initAnchors(W3CEvent) { for ( i=1 ; i<=5 ; i++ ) { var anchor = document.getElementById('anchor'+i); registerListener(anchor,i); } } ADS.addEvent(window, 'load', initAnchors);
由于click事件侦听器现在的外部作用域变成了registerListener()函数,该函数在它的每个实例的内部作用域中都为变量i维护了一个唯一的值,这一过程如下图所示:
如果修改registerListener()函数,提示的信息将是 My id is anchorX and initAnchors i is 4
这是因为变量的i的值不是在registerListener()函数中定义的,因此还要从initAnchors()函数的作用域中取得变量i的值,这个过程如下图所示:
6. 迭代对象
使用for循环对数组中的所有元素进行迭代:
var list = [1,2,3,4]; for( i=0 ; i<list.length ; i++ ) { alert(list[i]); }
需要注意的是当使用for(i in item)方法操纵类似数组时,例如由getElementsByTagName()返回的NamedNodeMap对象与数组类似,且具有length属性,也就是说可以像对一个常规数组一样对它进行迭代:
var all = document.body.getElementsByTagName('*'); for( i=0 ; i<all.length; i++){ // 对all[i]元素进行某些操作 }
但如果使用for(i in item)迭代方法,那么循环中还将包含NamedNodeMap对象的附加属性,即循环变量i的值也会分别等于length、item和namedItem,而这很可能会导致代码中出现意外错误。可以使用对象的hasOwnProperty()方法,如果对象的属性和方法是继承的,那么hasOwnProperty()方法会返回false,通过它可以只检查特定对象自身直接创建的属性,比如分配给数组的元素。因此循环会跳过length这样的属性。因为length属性不是数组all的直系属性,而是从自NamedNodeMap对象中继承的属性:
var all = document.body.getElementsByTagName('*'); for( i in all) { if(!all.hasOwnProperty(i)) { continue; } // 对all[i]元素进行某些操作 }
转载请注明:陈童的博客 » ADS1.3 JavaScript最佳实践——语法问题总结