第七章 函数表达式
,定义函数的方式有两种:一种是函数声明,另一种就是函数表达式。
函数声明:
sayHi();
function sayHi(){
alert(“Hi!”);
}
不会报错,因为在代码执行之前会先读取函数声明。
函数表达式:
var functionName = function(arg0, arg1, arg2){
//函数体
};编写递归函数时
var factorial = (function f(num){
if (num <= 1){
return 1;
} else {
return num * f(num-1);
}
});
以上代码创建了一个名为f()的命名函数表达式,然后将它赋值给变量factorial。即便把函数
赋值给了另一个变量,函数的名字f 仍然有效,所以递归调用照样能正确完成。这种方式在严格模式和
非严格模式下都行得通。闭包是指有权访问另一个函数作用域中的变量的函数。
闭包有权访问包含函数内部的所有变量,原理如下。
在后台执行环境中,闭包的作用域链包含着它自己的作用域、包含函数的作用域和全局作用域。
通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。
但是,当函数返回了一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止。
副作用,即闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
这个函数会返回一个函数数组。表面上看,似乎每个函数都应该返自己的索引值,即位置0 的函数返回0,位置1 的函数返回1,以此类推。但实际上,每个函数都返回10。因为每个函数的作用域链中都保存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;
}闭包会引用包含函数的整个活动对象,而其中包含着element。即使闭包不直接引用element,包含函数的活动对象中也仍然会保存一个引用。因此,有必要把element 变量设置为null。这样就能够解除对DOM 对象的引用,顺利地减少其引用数,确保正常回收其占用的内存。
function(){
//这里是块级作用域
}(); //出错!
这段代码会导致语法错误,是因为JavaScript 将function 关键字当作一个函数声明的开始,而函
数声明后面不能跟圆括号。然而,函数表达式的后面可以跟圆括号。要将函数声明转换成函数表达式,
只要像下面这样给它加上一对圆括号即可。
(function(){
//这里是块级作用域
})();无论在什么地方,只要临时需要一些变量,就可以使用私有作用域,例如:
function outputNumbers(count){
(function () {
for (var i=0; i < count; i++){
alert(i);
}
})();
alert(i); //导致一个错误!
}
这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链了。在这个函数内部,有3 个私有变量:num1、num2 和sum。在函数内部可以访问这几个变量,但在
函数外部则不能访问它们。如果在这个函数内部创建一个闭包,那么闭包通过自己的作用域链也可以访
问这些变量。而利用这一点,就可以创建用于访问私有变量的公有方法.
我们把有权访问私有变量和私有函数的公有方法称为特权方法(privileged method)。有两种在对象
上创建特权方法的方式。第一种是在构造函数中定义特权方法,基本模式如下。
function Person(name){
this.getName = function(){
return name;
};
this.setName = function (value) {
name = value;
};
}
var person = new Person("Nicholas");
alert(person.getName()); //"Nicholas"
person.setName("Greg");
alert(person.getName()); //"Greg"通过在私有作用域中定义私有变量或函数,同样也可以创建特权方法
(function(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//构造函数
MyObject = function(){
};
//公有/特权方法
MyObject.prototype.publicMethod = function(){
privateVariable++;
return privateFunction();
};
})();模块模式(modulepattern)则是为单例创建私有变量和特权方法