1.变量作用域
要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。
看代码
var n=999;
function f1(){
alert(n);
}
f1(); // 999
另一方面,在函数外部自然无法读取函数内的局部变量。
Js代码
function f1(){
var n=999;
}
alert(n); // error
这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!
Js代码
function f1(){
n=999;
}
f1();
alert(n); // 999
2.如何从外部读取局部变量?
出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。
那就是在函数的内部,再定义一个函数。
先看代码:
function f1(){
n=999;
function f2(){
alert(n); // 999
}
}
f2能访问到f1的变量
Javascript语言特有的“链式作用域”结构,子对象会一级一级地向上寻找所有父对象的变量。
所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!
再看:
function f1(){
var n=888;
function f2(){
alert(n)
}
return f2;
}
var result = f1();
console.log(result)
结果:
//f2(){
console.log(n)
}
//然后在代码后再执行如下代码,
result();//888,其实就是f2函数调用,
综合来看就是在函数体f1外边调用了函数的局部变量
3.深度理解
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //The Window
解析:object.getNameFunc()得到的结果是内部的function,然后在自执行,此时this指向window
再看:
function outerFun()
{
var a =1;
alert(a);
}
var a=3;
outerFun();
alert(a);
结果是 ?? .
再看下面的代码:
function outerFun()
{
//没有var
a =1;
alert(a);
}
var a=4;
outerFun();
alert(a);
结果为??他们两次的结果不一样,真是奇怪,为什么呢?
4.两种形式
a)函数作为返回值
eg:
function f1(){
var a =100;
function f2(){
console.log(a)
}
return f2
}
f1()();//100
b)函数作为参数
eg:
var num = 10;
var f2 = function (x) {
x = x > num ? x : num;
console.log(x)
};
(function(f){
var num=50;
f(30)
})(f2) //30
值得注意的是:代码运行,得到
var num = 50;
f2(30)//执行时取得是window下的num值,因为f2在window下创建的
自由变量跨作用域取值时:要去创建这个函数的作用域取值,而不是“父作用域”;
5.用处
eg:
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
var btns = document.getElementsByTagName("button");
for(var i =0;i<btns.length;i++){
btns[i].onclick = (function () {
console.log(i)
})
}
等到的结果是:4,4,4,4
for(var i =0;i<btns.length;i++){
btns[i].onclick = (function (a) {
return function () {
console.log(a)
}
})(i)
}
得到的结果是:0,1,2,3
所以:
for(var i =0;i<btns.length;i++){
btns[i].onclick = (function () {
btns[a].style.background ="red"
}
}
//上述代码会报错;???
for(var i =0;i<btns.length;i++){
btns[i].onclick = (function (a) {
return function () {
btns[a].style.background ="red"
}
})(i)
}
解析:
for(var i =0;i<btns.length;i++){
btns[i].onclick = change(i);
function change(a) {
return function () {
btns[a].style.background ="red"
}
}
}
//就能实现点击变色
6.总结
f1()调用完成。按理说应该销毁掉f1()的执行上下文环境,但是这里不能这么做,
因为执行f1()时,返回的是一个函数。函数的特别之处在于可以创建一个独立的作用域。
而正巧合的是,返回的这个函数体中,还有一个自由变量a要引用f1作用域下的f1()上下文环境中的a。
因此,这个max不能被销毁,销毁了之后f2函数中的a就找不到值了。
因此,这里的f1()上下文环境不能被销毁,还依然存在与执行上下文栈中。
eg:
function f1(){
var a =100;
function f2(){
console.log(a)
}
return f2
}
f1()()//100
[详情参考](http://www.cnblogs.com/wangfupeng1988/p/3994065.html);