JavaScript 函数表达式 闭包
创建函数有两种方式:一种是函数声明,另一种是函数表达式
1.函数声明
function functionName(i,j){
//函数体
}
说明:首先是函数关键字function,然后是函数的名字functionName。
最大的特征:函数声明提升,这就意味着函数声明可以放在调用它的语句之后
sayHi();//函数调用在前
function sayHi(){//函数声明在后
alert("hi");
}
2.函数表达式
最常见的方式如下:
var functionName=function(i,j){
//函数体
}
说明:形式很像变量赋值语句,即创建一个函数并将它赋给变量functionName。这种情况下创建的函数叫做匿名函数(也叫拉姆达函数),因为function关键字后面没有标识符。
重要特征:必须先声明再调用。
sayHi();//错误:函数不存在
var sayHi=function(){
alert("Hi);
}
闭包
闭包是指:有权访问另一个函数作用域中的变量的函数 闭包常见的创建方式:在一个函数内部创建另一个函数。
function createComparsionFunction(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;
}
;
}
//创建函数
var compareNames=creatComparsionFunction("name");
//调用函数
var result=compareNames({name:"Nicholas"},{name:"Greg"});
//解除对匿名函数的引用(以便释放内存)
compareNames=null;
说明:在匿名函数从createComparsionFunction()中被返回后,它的作用域被初始化为包含 createComparsionFunction()函数的活动对象和全局变量对象。
更重要的是: createComparsionFunction()函数在执行完毕后,它的活动对象也不会被销毁!!!,因为匿名函数的作用域链仍然在引用这个活动对象。
换句话说:当createComparsionFunction()函数返回后,其作用域链被销毁,但其活动对象仍然在内存中,直到匿名函数被销毁之后才销毁。
通过compareNames=null,解除该函数的引用,等于通知垃圾回收例程将其回收。随着匿名函数的作用域链被销毁,其他作用域(除了全局作用域)也都可以安全的销毁了。
- 闭包的副作用:即闭包只能取得包含函数(外部函数)中任何变量的最后一个值,注意哦是最后一个!!!
function createFunctions(){
var result=new Array();
for (var i=0; i<10; i++){
result[i]=function(){//这是一个闭包,也是匿名函数
return i;
};
//result[]里面保存的都是10,而不是期望的索引值0到9.
//什么情况看后面!!!
return result;
}
**解释:每个匿名函数的作用域链中都保存这createFunction()函数的活动对象。就像其前面所说的当createFunction()函数返回后,其作用域链被销毁,但其活动对象仍然在内存中,直到匿名函数被销毁之后才销毁。 它返回之后i=10。而每个函数都引用了保存这个变量i的活动对象,所以每个函数的内部都是10
- 解决方法:创建另一个匿名函数强制让闭包的行为符合预期
function createFunctions(){
var result=new Array();
for (var i=0; i<10; i++){
result[i]=function(num){
//再创建一个匿名函数,有一个参数num
//每次调用时都将变量i的当前值赋给参数num
return function(){
//创建一个返回num的闭包
return num;
};
}(i);//每次调用时都将变量i的当前值赋给参数num
//这样result[]中的每个函数都有自己num变量的一个副本,因此能返回各个不同的值
}
//result[]里面保存的是期望的索引值0到9.
return result;
}
-
闭包中的this对象
我们知道this对象在运行时基于函数的执行环境绑定的:在全局函数中,this等于window对象。而当函数被作为某个对象的方法调用时,this等于那个对象。
不过匿名函数的执行环境具有全局性,因此this对象通常指向window对象
var name="The Window",
var object={
name:"my boject";
getNameFunction:function(){
return function(){
rerurn this.name;
};
}
}
alert(object.getNameFunction()());//The Window
//object.getNameFunction()返回一个函数
//object.getNameFunction()()立即调用返回的这个函数
解决:将外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问这个对象了
var name="The Window",
var object={
name:"My Object";
getNameFunction:function(){
var that=this;//外部的this对象保存在that中
return function(){
rerurn that.name;//而不是this.name
};
}
}
alert(object.getNameFunction()());//My Object