在JavaScript中,函数也是一个对象,所有就可以看到如下的现象
所有在Java中等同于Class的构造器,其类型都是function。在JavaScript的世界中,我们可以将函数当作对象使用。
函数的声明方式:
//最常见的函数声明方式
function test(){
}
test();
//将匿名函数赋值给变量
var test2=function(){
}
test2();
//即时函数,因为该函数没有名称,也没有变量存储其引用,在第一次调用后就会被GC回收
(function(){
})();
而函数中,一个十分重要的概念就是闭包
var test=function(){
var tmp=0;
return function(){
debugger;
var a=tmp+1;
return a;
}
}
test()();
可以看到,test是一个函数,该函数的返回值是另一个函数,函数有作用域的概念,我们姑且称test的作用域为A,返回函数的作用域为B
那么在作用域B中使用到了作用域A中的值,这种现象称之为闭包
通过Chrome的开发者模式,我们可以发现:
在调用返回函数的时候,会有三个作用域,Global / Local / Closure(test),也就是当存在上述现象时,B作用域会保存A作用域的引用,当使用到A作用域的值时,就会从A作用域取值。
此时我们可以发现,对外界而言,也就是test之外的部分,tmp的值是不可见的,但通过test的返回值我们有能力使用到tmp,由此我们可以利用闭包来完成这种变量的私有化以及共享。
var test=function(begin){
var tmp=begin;
return function(){
return console.log(++tmp);
}
}
var a=test(1);
a();//2
a();//3
a();//4
上例就可以看出,虽然调用了多次a函数,但是tmp的值是累加的,因为每次a函数调用都在操作同一个tmp。
另一个使用场景如下:
var test=function(){
for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i);
},i*100);
}
}
test();
实际上该段代码会在控制台输入10次10。其原因是函数调用的顺序问题,所有的console.log因为计时器的关系,都会等待test函数执行完毕后进行调用,而当test函数执行结束后i将会被赋值为10,此时在继续调用计数器回调函数,输出的值就都是10了。我们可以利用匿名函数调用的方式
var test=function(){
for(var i=0;i<10;i++){
(function(i){
setTimeout(function(){
console.log(i);
},i*100);
})(i);
}
}
test();
因为函数作用域的关系,每次for循环的i都会被保存到副本中。