1.函数表达式与函数声明
在JavaScript中,定义函数有两种方式,一种是函数声明,一种是函数表达式。
函数声明的语法如下:
function functionName(arg0,arg1){
//函数体
}
函数表达式的语法如下:
var functionName=function(arg0,arg1){
//函数体
};
这两种方法有着一下的区别:
第一、函数声明有一个重要特征就是函数声明提升(function declaration hoisting),就是说在代码执行之前会先读取函数声明,因此可以将执行放在函数声明的前面。而函数表达式不具有这个特征。如对于以下代码:
sayHi();
function sayHi(){
alert("Hi!");
}
上面这个例子采用的是函数声明,所以不会有问题。
sayHi(); //错误:函数还不存在
var sayHi=function(){
alert("Hi!");
};
而这个例子由于采用的是函数表达式,无法再执行时读取函数声明,所以会出现错误。
第二、函数表达式可以像普通变量一样作为函数的结果返回,因此函数表达式可以用来实现递归,构造闭包,而函数声明不可以。
2.闭包以及闭包的几个用途
首先搞清闭包的概念:闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
要想很好的理解闭包的概念,首先来看下下面的这个例子。
function outer(argOut){
return function(argIn1,argIn2){
return argOut+argIn1+argIn2;
};
}
var addWithOuter=outer("a");
var result=addWithOuter("b","c"); //result为"abc"
var addWithOuter=null;
在上面的例子中,outer函数内部声明了一个匿名函数,根据JavaScript的作用域链机制(如果对这个概念不了解,请戳
JavaScript学习笔记之作用域链),内部匿名函数可以访问外部函数的变量argOut,也就是说它可以访问另一个函数(outer)的作用域中的变量,因此就构成了一个闭包。但是构成了闭包又怎么样呢?没什么大惊小怪的啊好像。。。。
咳咳,下面重点来了,当调用outer函数,并将结果函数返回给变量addWithOuter时,按照正常的逻辑,这个函数调用完之后,它的活动对象包括函数内的一些变量应该被销毁,也就是说这里的“a”应该就被销毁了,但是,有了闭包情况就不同了。我们可以看到,在后面继续调用addWithOuter指向的函数(因为outer返回给它的就是一个函数)时,依旧能访问变量“a”并返回正确的结果“abc”,也就是说对于闭包的情况,外层函数的活动对象没有随着函数调用结束而销毁。这是为什么呢?
根据JavaScript的作用域链机制,匿名函数的作用域链引用着外层函数的活动对象,因此当外层函数调用结束时,由于匿名函数还存在(被返回给了一个变量),而且其作用域链还在引用着外层函数的活动对象,因此外层函数的活动对象不会销毁,只会销毁外层函数的作用域链(指向活动对象的指针链)。直到解除addWithOuter的引用,才会销毁匿名函数的作用域链,外层的活动对象也就随着销毁了。
闭包的这种作用域链机制会占用比较多的内存,可能会导致IE9之前版本的IE浏览器发生内存泄露的问题。此外这种机制也决定了闭包只能取得包含函数中任何变量的最后一个值。
那么闭包有什么用途呢?
第一、闭包可以模仿块级作用域
(functon(){
//这里是块级作用域
})();
注意上面最后的“()”,表示函数直接执行,而块级作用域里的变量会随着匿名函数的执行完毕而立即销毁。
第二、闭包可以用于在对象中构造私有变量
function Person(name){
this.getName=function(){
return name
};
this.setName=function(value){
this.name=value;
};
}
function createFunctions(){
var result=new Array();
for(var i=0;i<10;i++){
result[i]=function(num){
return function(){
return num;
};
}(i);
}
}
这里我当时想的是为什么不直接改成返回一个return num;不就OK了,为啥还要返回一个function(){ return num;}?其实,如果直接return num这里保存在result里的数字确实也是0,1,2。。。。9,但是问题是这就不是闭包作用的体现了,这里主要是想讲给结果result返回一个函数,因为闭包的作用的体现很多时候就体现在返回一个函数。因此这里返回一个函数作为result的一项,加“()”运行这些函数项将会得到0,1,2。。。。9的结果。而如果想return num的话,那还莫不如直接result[i]=i;呢。。。。还何必费这事。。。= =愚蠢。。。
欢迎各位拍砖指正。