浅谈JavaScript代码优化

  本文主要从以下几个方面串烧如何优化我们的JavaScript代码——

  1>变量类型和变量声明
  2>等号(==)和非等号(!=)
    全等号(===)和非全等号(!==)
  3>逻辑与(&&)运算和逻辑或(||)运算
  4>函数声明 vs 函数表达式
  5>命名空间
  6>分号和空格

  主要是从让代码更加简洁、更加美观的角度去思考总结在书写JavaScript代码需要注意的要点——

  1 (function($){
  2     
  3     var namespace = {};
  4     
  5     namespace.basevar = function () {
  6         /**
  7          * 基本数据类型:number、字符串、布尔值、null和undefined
  8          */
  9         console.log(typeof 89.6);         //number
 10         console.log(typeof 'xxx');        //string
 11         console.log(typeof true);         //boolean
 12         console.log(typeof null);         //object,这个值来的比较诡异
 13         console.log(typeof undefined);    //undefined
 14         /**
 15          * 其余的类型我们均可以以对象的类型去看待,可能比较歧义的地方就是字符串string和数组array了,
 16          * 需要记住,在js中任意字符串均属于string类型,任何数组均属于object类型
 17          * 当我们需要创建数组和对象的时候,避免使用new Object和new Array方式,我们用{}和[]来代替
 18          */
 19     };
 20     
 21     function test() {
 22         /**
 23          * 在JavaScript中,我们不提倡在变量第一次使用时才被声明,在函数的开始部分声明所有变量,是一个非常好的编程实践。
 24          * 在这里,介绍一下单变量的声明方式,大叔的博客介绍的很详细,其好处在于
 25          * 1>提供了一个单一的地方去寻找功能所需要的所有局部变量
 26          * 2>防止变量在定义之前使用的逻辑错误
 27          * 3>少代码(类型和传值单线完成)
 28          */
 29         var obj = {};  //初始化变量的同时初始化值,这是一个好的编程实践,当我们再次看到代码的时候,我们就知道这些变量的大致用途
 30         var array = [];
 31         var xxx = null;
 32         var yyy = undefined;
 33         //我们可以替换成为——
 34         var obj = {},
 35             array = [],
 36             xxx = null,
 37             yyy = undefined;
 38         
 39         //当我们去判断一个对象真的是对象时,首先需要先排除它并不是null,是因为typeof null的值是object
 40         console.log(typeof null);      //object
 41         
 42         if (array && typeof array === 'object') {
 43             //数组是一个对象,不要忘记了这点
 44             //但同时,对象也是对象,我们再严格去判断数组的时候,可以这样写——
 45             if (array && typeof array === 'object' && array.constructor === Array) {
 46                 alert('array is a Array');
 47             }
 48             alert('array is a Object');
 49         }
 50         
 51         //当判断某一个值真的是null的时候,我们直接用以下方式最为简洁
 52         xxx === null && console.log(xxx);    //null
 53         //当然我们去判断undefined值的时候,同样如此——
 54         yyy === undefined && console.log(yyy);
 55         
 56         //关于相等或不相等的判断,是一个令人头痛的事情,因为规则多而杂。以下摘自《JavaScript高级程序设计-第3版》
 57         /**
 58          * 我们先理清一个概念:
 59          *     ==和!= :等号和非等号
 60          *     ===和!== :全等号和非全等号
 61          * 先看等号==和非等号!=的运算规则:
 62          *     1>如果一个运算数是Boolean值,在检查相等性之前,把它转换成数字值。false转换为0,true转换为1。
 63          *       true == 1;         //true
 64          *       false == 0;        //true
 65          *       true == 2;         //false
 66          *     2>如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。
 67          *         '5' == 5;         //true
 68          *     3>如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串(调用toString()方法)。
 69          *         //任意一个对象的toString()方法都返回一个字符串"[object Object]",紧接着就拿这个字符串和比对字符串进行比较了
 70          *         //确实有些晕乎了,JavaScript中的对象都可以理解为键值对的集合,我们所比较的应该是该对象里的某一个属性值和这个字符串是否相等
 71          *     4>如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换为数字。
 72          *     5>值null和undefined相等。
 73          *         null == undefined;      //true
 74          *     6>在检查相等性时,不能把null和undefined转换成其他值。
 75          *         undefined == 0;         //false
 76          *         null == 0;              //false
 77          *     7>如果某个运算数是NaN,等号将返回false,非等号将返回true。NaN不等于NaN
 78          *         NaN == 5                //false
 79          *         NaN != 5                //true
 80          *         NaN == NaN              //false
 81          *         NaN == 'NaN'            //false
 82          *     8>如果两个运算数都是对象,那么比较的是它们的引用值。如果两个运算数指向同一个对象,那么等号返回true。
 83          */
 84         /**
 85          * 对于全等号和非全等号,和等号和非等号都差不多,只不过它们在检查相等性前,不执行类型转换。
 86          * 只有在无类型转换运算数就相等的情况下,才返回true。
 87          * 我们建议不要使用等号==和非等号!=进行判断,相反的,始终使用全等号===和非全等号!==,这会提高我们代码的阅读性。
 88          * 如果我们希望使用强制类型转换,那么就使用简易格式,如:
 89          *     if (foo) {...}         //而不是if (foo != 0) {...}
 90          *     if (!foo) {...}        //而不是if (foo == 0) {...}
 91          */
 92         /**
 93          * 谈完了等性运算符,我们常常把等性运算与逻辑与'&&'运算及逻辑或'||'运算结合在一起进行应用,
 94          * 来看看||和&&用在什么场景:
 95          *     1>||运算符可以用来填充默认值
 96          *         var str = str || '';    //毫无疑问,提高了程序的健壮性
 97          *     2>&&运算符可以避免错误
 98          *         //当obj没有equipment属性或者obj.equipment === ''(null) 的时候,后面语句也就不执行了,
 99          *         //防止直接访问model属性时,产生的错误
100          *         obj.equipment && obj.equipment.model
101          *         //这句代码是老相识了,简单的理解它为单线程的if判断,让代码看起来比较简洁和优雅
102          *         $.browser.msie && $.browser.version <= 6 && ...
103          */
104     }  //test函数结束
105     /**
106      * 在上面呢,我们用的是函数声明的方式定义函数,function语句在解析时会发生被提升的情况(讲的不是很官方,不过,却非常好理解)。
107      * 这意味着不管function在哪里,它都会被移动到被定义时所在作用域的顶层。这放宽了函数必须先声明后使用的要求。
108      * 不过,它在一定程度上会导致混乱。当我们的代码非常之多的时候,维护起来就有些难了。提倡使用函数表达式的形式
109      *     var foo = function foo() {...};     //而不是function foo() {...}
110      *                                         //至于为什么function右边为什么再次声明了函数名foo,debug一下,看看调用栈就知道了。
111      *                                         //当然,实际编写代码的时候,没有必要加
112      * 最主要的是,当我们采用的是函数表达式的方式定义函数的时候,我们可以让这个函数对象赋值进一个命名空间,
113      * 让每一个对象都有自己的命名空间,可以让我们很容易使用对象去管理代码。当然,这里的命名空间仅仅是一个对象而已。
114      * 命名空间再结合闭包(模块模式)的使用,不仅能够减少全局变量的污染,更加提高了代码的封装性。
115      */
116     
117     /**
118      * 这里要注意的是,如果一个return语句返回一个值,这个值表达式的开始部分必须和return在同一行上。
119      */
120     namespace.block = function () {
121 //      return    //undefined
122 //      {
123 //          num  :  100
124 //      };
125         return {  //object
126             num  :  100
127         };
128         /**
129          * 另外——
130          * 1>我们最好始终要用一对花括号来包住我们的代码块。
131          * 2>'{' 放在一行的结尾,而不是下一行的开头
132          */
133     };
134     /**
135      * 对于分号,JSLint期望除了for、function、if、switch、try和while之外的每一个语句后面都跟着分号。
136      */
137     /**
138      * 对于空格,大叔博客总结得到位,拷贝下——
139      * 1>for循环分号分开后的的部分:如for (var i = 0; i < 10; i += 1) {...}
140      * 2>for循环中初始化的多变量(i和max):for (var i = 0, max = 10; i < max; i += 1) {...}
141      * 3>分隔数组项的逗号的后面:var a = [1, 2, 3];
142      * 4>对象属性逗号的后面以及分隔属性名和属性值的冒号的后面:var o = {a: 1, b: 2};
143      * 5>限定函数参数:myFunc(a, b, c)
144      * 6>函数声明的花括号的前面:function myFunc() {}
145      * 7>匿名函数表达式function的后面:var myFunc = function () {};
146      * 8>操作符和操作对象之间,这意味着在+, -, *, =, <, >, <=, >=, ===, !==, &&, ||, +=等前后都需要空格。
147      * 9>if-else语句、循环、对象字面量的左花括号的前面
148      * 10>else或while之间的右花括号
149      */
150     
151     /**
152      * --------------------------------------------------------------------
153      * 参考文章——
154      *     《JavaScript语言精粹》——
155      *         第3章——对象
156      *         第9章——代码风格
157      *         第10章——优美的特性
158      *         附录A——糟粕
159      *         附录B——鸡肋
160      *         附录C——JSLint
161      *     《JavaScript高级程序设计-第3版》——
162      *         第2章——ECMAScript基础
163      *     汤姆大叔的博客——
164      *         深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点
165      *         深入理解JavaScript系列(2):揭秘命名函数表达式
166      * --------------------------------------------------------------------
167      */
168     
169 })(jQuery);