11. log(b);
12. varb=i*i;
13. }
14.
15. if(a===10){
16. f=function(){
17. log(a);
18. };
19. f();
20.
21. varf;
22. }
23.
24. functionx(){
25. log('Mr.X!
');
26. }
27.
28.}(window.console.log));
复制代码
正如你所看到的这段令人充满困惑与误解的代码导致了出人意料的结果。
只有良好的声明习惯,也就是下一章节我们要提到的声明规则,才能尽可能的避免这类错误风险。
提升声明
为避免上一章节所述的变量和方法定义被自动提升造成误解,把风险降到最低,我们应该手动地显示地去声明变量与方法。
也就是说,所有的变量以及方法,应当定义在function内的首行。
只用一个var关键字声明,多个变量用逗号隔开。
不推荐
1.(function(log){
2. 'usestrict';
3.
4. vara=10;
5. varb=10;
6.
7. for(vari=0;i<10;i++){
8. varc=a*b*i;
9. }
10.
11. functionf(){
12.
13. }
14.
15. vard=100;
16. varx=function(){
17. returnd*d;
18. };
19. log(x());
20.
21.}(window.console.log));
复制代码
推荐
1.(function(log){
2. 'usestrict';
3.
4. vara=10,
5. b=10,
6. i,
7. c,
8. d,
9. x;
10.
11. functionf(){
12.
13. }
14.
15. for(i=0;i<10;i++){
16. c=a*b*i;
17. }
18.
19.
20.
21. d=100;
22. x=function(){
23. returnd*d;
24. };
25. log(x());
26.
27.}(window.console.log));
复制代码
把赋值尽量写在变量申明中。
不推荐
1.vara,
2. b,
3. c;
4.
5.a=10;
6.b=10;
7.c=100;
复制代码
推荐
1.vara=10,
2. b=10,
3. c=100;
复制代码
总是使用带类型判断的比较判断
总是使用===精确的比较操作符,避免在判断的过程中,由JavaScript的强制类型转换所造成的困扰。
如果你使用===操作符,那比较的双方必须是同一类型为前提的条件下才会有效。
如果你想了解更多关于强制类型转换的信息,你可以读一读DmitrySoshnikov的这篇文章。
在只使用==的情况下,JavaScript所带来的强制类型转换使得判断结果跟踪变得复杂,下面的例子可以看出这样的结果有多怪了:
1.(function(log){
2. 'usestrict';
3.
4. log('0'==0);//true
5. log(''==false);//true
6. log('1'==true);//true
7. log(null==undefined);//true
8.
9. varx={
10. valueOf:
function(){
11. return'X';
12. }
13. };
14.
15. log(x=='X');
16.
17.}(window.console.log));
复制代码
明智地使用真假判断
当我们在一个if条件语句中使用变量或表达式时,会做真假判断。
if(a==true)是不同于if(a)的。
后者的判断比较特殊,我们称其为真假判断。
这种判断会通过特殊的操作将其转换为true或false,下列表达式统统返回false:
false,0,undefined,null,NaN,''(空字符串).
这种真假判断在我们只求结果而不关心过程的情况下,非常的有帮助。
以下示例展示了真假判断是如何工作的:
1.(function(log){
2. 'usestrict';
3.
4. functionlogTruthyFalsy(expr){
5. if(expr){
6. log('truthy');
7. }else{
8. log('falsy');
9. }
10. }
11.
12. logTruthyFalsy(true);//truthy
13. logTruthyFalsy
(1);//truthy
14. logTruthyFalsy({});//truthy
15. logTruthyFalsy([]);//truthy
16. logTruthyFalsy('0');//truthy
17.
18. logTruthyFalsy(false);//falsy
19. logTruthyFalsy(0);//falsy
20. logTruthyFalsy(undefined);//falsy
21. logTruthyFalsy(null);//falsy
22. logTruthyFalsy(NaN);//falsy
23. logTruthyFalsy('');//falsy
24.
25.}(window.console.log));
复制代码
变量赋值时的逻辑操作
逻辑操作符||和&&也可被用来返回布尔值。
如果操作对象为非布尔对象,那每个表达式将会被自左向右地做真假判断。
基于此操作,最终总有一个表达式被返回回来。
这在变量赋值时,是可以用来简化你的代码的。
不推荐
1.if(!
x){
2. if(!
y){
3. x=1;
4. }else{
5. x=y;
6. }
7.}
复制代码
推荐
1.x=x||y||1;
复制代码
这一小技巧经常用来给方法设定默认的参数。
1.(function(log){
2. 'usestrict';
3.
4. functionmultiply(a,b){
5. a=a||1;
6. b=b||1;
7.
8. log('Result'+a*b);
9. }
10.
11. multiply();//Result1
12. multiply(10);//Result10
13. multiply(3,NaN);//Result3
14. multiply(9,5);//Result45
15.
16.}(window.console.log));
复制代码
分号
总是使用分号,因为隐式的代码嵌套会引发难以察觉的问题。
当然我们更要从根本上来杜绝这些问题[1]。
以下几个示例展示了缺少分号的危害:
1.//1.
2.MyClass.prototype.myMethod=function(){
3. return42;
4.} //Nosemicolonhere.
5.
6.(function(){
7. //Someinitializationcodewrappedinafunctiontocreateascopeforlocals.
8.})();
9.
10.
11.varx={
12. 'i':
1,
13. 'j':
2
14.} //Nosemicolonhere.
15.
16.//2. TryingtodoonethingonInternetExplorerandanotheronFirefox.
17.//Iknowyou'dneverwritecodelikethis,butthrowmeabone.
18.[ffVersion,ieVersion][isIE]();
19.
20.
21.varTHINGS_TO_EAT=[apples,oysters,sprayOnCheese] //Nosemicolonhere.
22.
23.//3.conditionalexecutionalabash
24.-1==resultOfOperation()||die();
复制代码
Sowhathappens?
JavaScript错误——首先返回42的那个function被第二个function当中参数传入调用,接着数字42也被“调用”而导致出错。
八成你会得到‘nosuchpropertyinundefined’的错误提示,因为在真实环境中的调用是这个样子:
x[ffVersion,ieVersion][isIE]().
die总是被调用。
因为数组减1的结果是NaN,它不等于任何东西(无论resultOfOperation是否返回NaN)。
所以最终的结果是die()执行完所获得值将赋给THINGS_TO_EAT.
Why?
JavaScript中语句要以分号结束,否则它将会继续执行下去,不管换不换行。
以上的每一个示例中,函数声明或对象或数组,都变成了在一句语句体内。
要知道闭合圆括号并不代表语句结束,JavaScript不会终结语句,除非它的下一个token是一个中缀符[2]或者是圆括号操作符。
这真是让人大吃一惊,所以乖乖地给语句末加上分号吧。
澄清:
分号与函数
分号需要用在表达式的结尾,而并非函数声明的结尾。
区分它们最好的例子是:
1.varfoo=function(){
2. returntrue;
3.}; //semicolonhere.
4.
5.functionfoo(){
6. returntrue;
7.} //nosemicolonhere.
复制代码
嵌套函数
嵌套函数是非常有用的,比如用在持续创建和隐藏辅助函数的任务中。
你可以非常自由随意地使用它们。
语句块内的函数声明
切勿在语句块内声明函数,在ECMAScript5的严格模式下,这是不合法的。
函数声明应该在定义域的顶层。
但在语句块内可将函数申明转化为函数表达式赋值给变量。
不推荐
1.if(x){
2. functionfoo(){}
3.}
复制代码
推荐
1.if(x){
2. varfoo=function(){};
3.}
复制代码
异常
基本上你无法避免出现异常,特别是在做大型开发时(使用应用开发框架等等)。
在没有自定义异常的情况下,从有返回值的函数中返回错误信息一定非常的棘手,更别提多不优雅了。
不好的解决方案包括了传第一个引用类型来接纳错误信息,或总是返回一个对象列表,其中包含着可能的错误对象。
以上方式基本上是比较简陋的异常处理方式。
适时可做自定义异常处理。
在复杂的环境中,你可以考虑抛出对象而不仅仅是字符串(默认的抛出值)。
1.if(name===undefined){
2. throw{
3. name:
'SystemError',
4. message:
'Anameshouldalwaysbespecified!
'
5. }
6.}
复制代码
标准特性
总是优先考虑使用标准特性。
为了最大限度地保证扩展性与兼容性,总是首选标准的特性,而不是非标准的特性(例如:
首选string.charAt(3)而不是string[3];首选DOM的操作方法来获得元素引用,而不是某一应用特定的快捷方法)。
简易的原型继承
如果你想在JavaScript中继承你的对象,请遵循一个简易的模式来创建此继承。
如果你预计你会遇上复杂对象的继承,那可以考虑采用一个继承库,比如 Proto.jsbyAxelRauschmayer.
简易继承请用以下方式:
1.(function(log){
2. 'usestrict';
3.
4. //Constructorfunction
5. functionApple(name){
6.