定义函数的方式有两种:一种是函数声明,另一种就是函数表达式。
//函数声明的语法是这样的
function functionName(arg0, arg1, arg2) {//函数体} ```
//函数表达式有很多种,最常见的的语法是这样的
var functionName = function(arg0, arg1, arg2){//函数体}; ```
一、递归
function factorial(num){
if (num <= 1){
return 1;
} else {
return num * factorial(num-1);
}
}```
这是一个经典的递归阶乘函数。虽然这个函数表面看来没什么问题,但下面的代码却可能导致它出错。
var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4)); //出错! ```
arguments.callee 是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用,例如:
function factorial(num){
if (num <= 1){
return 1;
} else {
return num * arguments.callee(num-1);
}
} ```
在严格模式下,不能通过脚本访问 arguments.callee,访问这个属性会导致错误。不过,可以使用命名函数表达式来达成相同的结果。例如:
var factorial = (function f(num){
if (num <= 1){
return 1;
} else {
return num * f(num-1);
}
});```
以上代码创建了一个名为 f()的命名函数表达式,然后将它赋值给变量 factorial。即便把函数赋值给了另一个变量,函数的名字 f 仍然有效,所以递归调用照样能正确完成。这种方式在严格模式和非严格模式下都行得通。
二、闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数
1. 闭包与变量
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
} //返回数组内部是十个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;
} //返回数组内容是0-9```
2. 关于this对象
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //"The Window"(在非严格模式下) ```
每个函数在被调用时都会自动取得两个特殊变量: this 和 arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,永远不可能直接访问外部函数中的这两个变量。不过,把外部作用域中的 this 对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了,如下所示。
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"My Object" ```
3. 模仿块级作用域
JavaScript 没有块级作用域的概念。这意味着在块语句中定义的变量,实际上是在包含函数中而非语句中创建的
function outputNumbers(count){
for (var i=0; i < count; i++){
alert(i);
}
alert(i); //计数
}```
这个函数中定义了一个 for 循环,而变量 i 的初始值被设置为 0。在 Java、 C++等语言中,变量 i只会在 for 循环的语句块中有定义,循环一旦结束,变量 i 就会被销毁。可是在 JavaScrip 中,变量 i是定义在 ouputNumbers()的活动对象中的,因此从它有定义开始,就可以在函数内部随处访问它。
在一个由很多开发人员共同参与的大型应用程序中,过多的全局变量和函数很容易导致命名冲突。而通过创建私有作用域,每个开发人员既可以使用自己的变量,又不必担心搞乱全局作用域。例如:
(function(){
var now = new Date();
if (now.getMonth() == 0 && now.getDate() == 1){
alert("Happy new year!");
}
})(); ```
4. 私有变量
增强的模块模式
var singleton = function(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//创建对象
var object = new CustomType();
//添加特权/公有属性和方法
object.publicProperty = true;
object.publicMethod = function(){
privateVariable++;return privateFunction();
};
//返回这个对象
return object;
}(); ```