日期:2014-05-16  浏览次数:20285 次

如何书写高质量js代码
>>>>> 避免全局变量,因为全局变量容易发生名称上的冲突,可维护性不好。
	1,使用命名空间
	2,使用闭包
	3,在函数内部使用var声明
function sum(x,y){
     result = x + y;
     return result;
}
alert(window.result); 所有全局变量都是window的一个属性
如果调用sum函数,就会自动多一个result的全局变量,在javascript中,所有未声明的变量都会成为全局对象的一个属性

使用链式方法声明变量
function foo(){
     var a=b=0;
     ....
}
 虽然a是局部变量,但这样b就变成全局变量,这是因为,
 b = 0这个表达式先执行,执行的时候b并没有被声明,所以b就成为了全局变量,然后返回这个表达式的值0,给声明了的变量a
 如果你已经声明了var a,b这样是可以的。
 
 另外一个避免使用全局变量的原因是考虑到程序的可移植性。
 如果你想让你的代码在不同的环境中都可以工作,那么使用全局变量就很可能会与新的系统中的全局变量冲突(或许在之前的系统中没有问题)。
 
使用var声明的全局变量和没有使用var生成的全局变量还有一个区别在于删除:

使用var声明创建的全局变量不能被删除

没有使用var声明的全局变量可以被删除

这说明没有使用var声明生成的全局变量不是真正的变量,他们只是全局对象的属性。属性可以通过delete删除,但是变量不行

在你的代码的顶部只是用一个var关键字,会有以下的好处:
 对于所有需要的变量,在一个地方就可以全部看到 
 避免使用一个未定义的变量 
 帮助你记忆声明的变量,减少全局变量 
 更精简的代码 
 书写很简单
通过一个var和逗号来声明多个变量。
在声明的时候给变量赋默认值也是不错的做法,可以避免一些逻辑错误,提高代码的可读性。而后你阅读的代码的时候也可以根据变量的默认值来方便的猜测变量的用途。

JavaScript允许你在函数内部有多个var语句,但是却都表现的如同在函数的顶部声明一样。
这个特性在你使用一个变量然后在后面又声明了这个变量时会导致一些奇怪的逻辑问题。
对于JavaScript来说,只要变量在同一个作用域,那么就认为是声明了的,就算是在var语句之前使用也一样。看看这个例子:

myname = "global"; // global variable
function func() {
    alert(myname); // "undefined"
    var myname = "local";
    alert(myname); // "local"
}
func();

在这个例子中,或许你期望第一次会弹出global,第二次弹出local。
因为第一次的时候没有还没有使用var声明myname,这是应该是全局变量的myname,第二次声明了,然后alert之后应该是local的值。
而事实上不是这样的,只要你在函数中出现了var myname,那么js就认为你在这个函数中声明了这个变量,
但是在读取这个变量的值的时候,因为var语句还没有执行,所以是undefined,很奇怪的逻辑吧。上面的代码相当于:

myname = "global"; // global variable
function func() {
   var myname; // same as -> var myname = undefined;
   alert(myname); // "undefined"
   myname = "local";
   alert(myname); // "local"
}
func();

在代码的解析中,分两个步骤,第一步先处理变量函数的声明,
这一步处理整个代码的上下文。第二步就是代码的运行时,创建函数表达式以及未定义的变量。

>>>>>  for循环

for (var i = 0; i < myarray.length; i++) {
   // do something with myarray[i]
}

这样每次迭代都会计算数组的长度。尤其在这个参数不是一个数组而是一组HTML元素的时候会降低你的程序的性能。

for (var i = 0, max = myarray.length; i < max; i++) {
   // do something with myarray[i]
}

先保留长度,不用每次都计算。
在查找HTML元素集合的时候,缓存参数长度可以带来可观的性能提升,Safari下面提高两倍的速度,在IE7下面提高190倍的速度。
需要注意的是,当你需要操作修改DOM元素的数量的时候,你肯定希望这个值是随时更新的而不是一个常量。
使用下面的单一var模式,你也可以把var提到循环之外:
function looper() {
   var i = 0,
        max,
        myarray = [];
   // ...
   for (i = 0, max = myarray.length; i < max; i++) {
      // do something with myarray[i]
   }
}
这个模式可以增强整个代码的连续性,但是不好的一点是当你重构代码的时候复制粘贴就没那么容易了。
例如:如果你想在其他函数中也使用这个循环,那你需要确定在新的函数中处理好了i和max(或许还需要删掉这个)。

这个函数还有两个点可以优化的:

可以少一个变量(不需要max) 
递减到0,一个数字与0比较比这个数字与另外一个数字比较更快 
所以就可以写为:
var i, myarray = [];
for (i = myarray.length; i--;) {
   // do something with myarray[i]
}
针对第二点:

var myarray = [],
    i = myarray.length;
while (i--) {
   // do something with myarray[i]
}   
  :) 哟西。
  
  
>>>>>>> for in 循环 for-in循环用来迭代非数组的对象。使用for-in循环通常也成为枚举。

从技术上来说,你也可以用for-in来循环数组,因为数组也是对象,但是不推荐。如果数组有一些自定义的扩展函数,
那么就会出错。另外,对象属性的顺序在for-in循环中也是不确定的。所以最好还是用普通的循环来循环数组用for-in来循环对象

在循环对象的过程中,使用hasOwnProperty()方法来检验是对象本身的属性还是原型链上的属性很重要。
看看下面的这个例子。

// the object
var man = {
   hands: 2,
   legs: 2,
   heads: 1
}; 
 
// somewhere else in the code
// a method was added to all objects
if (typeof Object.prototype.clone === "undefined") {
   Object.prototype.clone = function () {};
}

在这个例子中,我们有一个简单的称作man的对象字面量。在其他man定义之前或之后的地方,对象原型有一个很有用的clone()方法。
因为原型链的原因,所有的对象都自动获得了这个方法。
为了在枚举man对象的时候出现clone方法,你需要使用hasOwnProperty方法来区别。如果没有区别来自原型链的方法,那么就会有一些意想不到的事情发生:

// 1.
// for-in loop
for (var i in man) {
   if (man.hasOwnProperty(i)) { // filter
      console.log(i, ":", man[i]);
   }
}
/* result in the console
hands : 2
legs : 2
heads : 1
*/
// 2.
// antipattern:
// for-in loop without checking hasOwnProperty()
for (var i in man) {
   console.log(i, ":", man[i]);
}
/*
result in the console
hands : 2
legs : 2
heads : 1
clone: function()
*/

另外一种使用方法如下:
for (var i in man) {
   if (Object.prototype.hasOwnProperty.call(man, i)) { // filter
      console.log(i, ":", man[i]);
   }
}

这样写的好处是可以防止