- 函数主体:
function functionName(arg0, arg1, arg2) {
//函数体
} - 常见的创建和调用函数的方式:
- sayHi();
function sayHi(){
alert("Hi!");
} - var functionName = function(arg0, arg1, arg2){
//函数体
};
1.递归
函数的递归是运用函数的一个小技巧,可以进行计算一些复杂的循环算法,进而减轻工作量!例如:
function factorial(num){
if (num <= 1){
return 1;
}
else {
return num * factorial(num-1);
} }
这是一个简单的递归函数,利用这样的的方式可以进行阶乘运算,但是,由于函数名有时候可能需要更改,如果因此忘记把下面递归的函数名一起更改,就会导致报错。因此,ECMAScript里面提供了一种更好的方法:
function factorial(num){
if (num <= 1){
return 1; }
else {
return num * arguments.callee(num-1);
}
}
如图,该方法就是将函数名替换成了arguments.calle,这样不管函数名是否变,都不影响函数的递归运算了。
2.闭包
创建闭包的常见方式,就是在一个函数内部创建另一个函数:
function createComparisonFunction(propertyName) { return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName]; if (value1 < value2){
return -1;
}
else if (value1 > value2){
return 1;
}
else {
return 0;
}
};
}
接下来要强调的是闭包的变量问题,作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的后一个值,因为闭包所保存的是整个变量对象,而不是某个特殊的变量,例如:
function createFunctions(){ var result = new Array();
for (var i=0; i < 10; i++){ result[i] = function(){ return i; }; }
return result; }
这里很好的阐述了变量的引用问题,因为每个函数的作用域链中 都保存着 createFunctions()函数的活动对象,所以它们引用的都是同一个变量 i。当 createFunctions()函数返回后,变量 i 的值是 10,此时每个函数都引用着保存变量 i 的同一个变量 对象,所以在每个函数内部 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; }
在这里,由于函数参数是按值传递的,所以就会将变量 i 的当前值复制给参数 num。而在这个 匿名函数内部,又创建并返回了一个访问 num 的闭包。这样一来,result 数组中的每个函数都有自己 num 变量的一个副本,因此就可以返回各自不同的数值了。
3.模仿块级作用域
JavaScript 没有块级作用域的概念。这意味着在块语句中定义的变量,实际上是在包含函数中而非语句中创建的。
块级作用域通常称为私有作用域,也即是定义的函数内的作用域,这里要特别强调的是在声明匿名函数时,需要用圆括号,避免Javascript将 function 关键字当作一个函数声明的开始,如:
function(){
//这里是块级作用域
}(); //出错
正确声明:
(function(){
//这里是块级作用域
})();
其他的函数的定义和声明可以进行如下操作:
var someFunction = function(){
//这里是块级作用域
};
someFunction();