var add =(function(){
var counter = 0;
return function(){
return counter += 1
}
})()
add() //1
add() //2
add() //3
疑问:为什么每次执行add()之后结果是递增的而不是都是1呢?
上面的函数可以拆解为
function test() {
var counter = 0;
return function() {
return counter += 1;
};
}
var add = test();
即将test
函数赋值给add
,add
是test
函数的返回值,即return counter += 1
test()
只在赋值的时候执行了一次,执行了三次add()
,每一次都有counter+=1
,add()
返回的counter
其实是引用了函数外定义的counter
一、函数声明和函数表达式的区别
- 函数声明不能加括号不会立即执行
- 函数表达式可以加括号立即执行
- 函数声明立即调用的方法:用“()”包起来形成函数表达式,加上括号立即使用
//函数声明
function f1(){
//...
}() //加括号会报错
//函数表达式
var functionName = function() {
//...
}() //加括号表示立即执行
//函数声明立即执行
(function f1(){
//...
})()
所以在这个例子中,由于函数被包含在()括号内,并在最后加了一个()表示立即执行函数,所以在运行代码的时候add其实变成了add = function () {return counter += 1;}
二、闭包
理解:
保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界的干扰。直观的说就是形成一个不销毁的栈环境。
特点:
- 闭包可以记住并访问词法作用域,即使得函数是在当前词法作用域外执行,就会形成闭包。闭包是指有权访问另一个函数作用域中的变量的函数
- 闭包有两种基本情况:闭包的返回值是一个函数,它其中使用了该闭包的局部变量;闭包内定义了内部函数,内部函数引用了闭包的局部变量
- 拥有更多长的生命周期
作用:
- 能在一个函数外访问函数中的局部变量
- 防止对全局作用域的污染
从闭包解释上面这段代码
- 执行
add
函数的时候并没有重新声明函数,立即执行该函数此时的返回值就一个闭包。每次调用add
函数实际上都是在使用这个闭包 - 闭包可以记住词法作用域的标识符(即这段代码中的
counter
),所以再次调用函数的时候可以记住上次累加的counter
的值