函数表达式

定义

定义函数的 方式有两种:一种是函数声明,另一种就是函数表达式

关于函数声明,它的一个重要特征就是函数声明提升


执行以下代码的结果可 能会让人意想不到

if(condition){ 
 function sayHi(){ 
 alert("Hi!"); 
 } 
} else { 
 function sayHi(){ 
 alert("Yo!"); 
 } 
} 

这在 ECMAScript 中属于无效语法,JavaScript 引擎会尝试修正错误,将其转换为合 理的状态。大多数浏览器会返回第二个声明。

修改

var sayHi; 
if(condition){ 
 sayHi = function(){ 
 alert("Hi!"); 
 }; 
} else { 
 sayHi = function(){ 
 alert("Yo!"); 
 }; 
} 


递归

function factorial(num){ 
 if (num <= 1){ 
 return 1; 
 } else { 
 return num * factorial(num-1); 
 } 
} 

减小耦合,但增大了内存开销。

function factorial(num){ 
 if (num <= 1){ 
 return 1; 
 } else { 
 return num * arguments.callee(num-1); 
 } 
}

闭包

闭包是指有权访问另一个 函数作用域中的变量的函数。

function createFunctions(){ 
 var result = new Array(); 
 for (var i=0; i < 10; i++){ 
 result[i] = function(){ 
 return i; 
 }; 
 } 
 return result; 
}

以它们引用的都是同一个变量 i 。 当 createFunctions()函数返回后,变量 i 的值是 10

修改

function createFunctions(){ 
 var result = new Array(); 
 for (var i=0; i < 10; i++){ 
 result[i] = function(num){ 
 return function(){ 
 return num; 
 }; 
 }(i);
 } 
 return result; 
}

在这个 匿名函数内部,又创建并返回了一个访问 num 的闭包


this对象

匿名函数的执行环境具有全局性,因此其 this 对象通常指向 window

var name = "The Window"; 
var object = { 
 name : "My Object", 
 getNameFunc : function(){ 
 return function(){ 
 return this.name; 
 }; 
 } 
}; 
alert(object.getNameFunc()()); //"The Window"

每个函数在被调用时都会自动取得两个特殊变量:this 和 arguments。内部函 数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量


var name = "The Window"; 
var object = { 
 name : "My Object", 
 getName: function(){ 
 return this.name; 
 } 
}; 



object.getName(); //"My Object" 
(object.getName)(); //"My Object" 
(object.getName = object.getName)(); //"The Window",

第二行代码在调用这个方法前先给它加上了括号。虽然加上括号之后,就好像只 是在引用一个函数,但 this 的值得到了维持,因为 object.getName 和(object.getName)的定义 是相同的。

第三行代码先执行了一条赋值语句,然后再调用赋值后的结果。因为这个赋值表达式的值是 函数本身,所以 this 的值不能得到维持,结果就返回了"The Window"。


内存泄漏

如果闭包的作用域链中保存着一个 HTML 元素,那么就意味着该元素将无法被销毁

function assignHandler(){ 
 var element = document.getElementById("someElement"); 
 element.onclick = function(){ 
 alert(element.id); 
 }; 
} 

由于匿名函数保存了一个对 assignHandler()的活动对象的引用,因此 就会导致无法减少 element 的引用数

修改

function assignHandler(){ 
 var element = document.getElementById("someElement"); 
 var id = element.id; 
 
 element.onclick = function(){ 
 alert(id); 
 }; 
 
 element = null; 
}

通过把 element.id 的一个副本保存在一个变量中,并且在闭包中引用该变量消 除了循环引用


模仿块级作用域

语法

(function(){ 
 //这里是块级作用域
})();

以上代码定义并立即调用了一个匿名函数,可以避免命名的变量被其他地方调用


私有变量

(function(){ 
    //私有变量
    var a 
    //私有函数
    function b(){
    	...  
    }
 (function(){ 
 //这里可以去调用
	})();
})();