首先說3點與閉包有關系的東西。
一、變量的作用域
變量的作用域不難理解。
1.函數內部可以訪問函數外部的變量,而函數外部不能訪問函數內部的變量。
2.如果在函數內定義變量的時候,不加var,那么是全局變量(當然函數要被調用過一次,未調用過則報錯:變量未定義)。加var,就是局部變量。
一個示例說明上面兩點。
1
2
3
4
5
6
7
8
9
10
|
function
f()
{
p1 =
"關羽"
;
var
p2 =
"劉備"
;
}
window.onload =
function
(){
f();
//當然,函數必須被調用一次,否則報找不到p1錯誤了
alert(p1);
//關羽
alert(p2);
//報錯:p2 is not defined
}
|
二、變量的生命周期
生命周期也不難理解。
1.全局變量生命周期為直到頁面被關閉。
2.在函數內通過var關鍵字聲明的局部變量在函數退出后就會失效。
三、匿名函數
這是一個匿名函數
1
2
3
|
setTimeout(
function
(){
alert(str);
//這是一個匿名函數
},2000);
|
匿名函數的幾種調用形式:
1
2
3
4
5
|
//通過引用調用匿名函數
func1 =
function
(){
alert(
"func1"
);
}
func1();
|
注意下面3個示例的 () 其實就同func1()這個括號一樣,是函數調用符。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//無引用的調用方式1
(
function
(){
}())
//無引用的調用方式2
(
function
(){
})()
//無引用的調用方式3
void
function
(){
}();
|
前面的小括號定義匿名函數,后面的小括號調用此匿名函數。記住它的樣子喔,不然后面看不懂。
四、閉包
閉包其實說的是這樣一種現象:
函數A內部的函數B,被函數A外的變量引用着。函數A內的環境不會銷毀(即函數A內的變量永久存在)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
var
func1 =
function
(){
var
a = 1;
//退出函數,局部變量丟失
alert(a++);
}
func1();
//彈出1
func1();
//彈出1
var
func2 =
function
(){
var
a = 1;
var
func3 =
function
(){
alert(a++);
}
return
func3;
}
var
f = func2();
//func2() 必須先調用一次,才能形成閉包
f();
//彈出1
f();
//彈出2其內部的a並沒有清空。
|
此處要特別注意的是,要形成閉包,首先必須先調用一次外層函數。
例如上面的 f ,f引用這函數內的函數func3,而func3是可以訪問到a的,所以a也可能會被f引用到。只要f不清空,a也不能銷毀。
上面的代碼是為了方便理解,實際開發中大多使用匿名函數,這樣代碼量會更少,而且特別適合裝逼。
1
2
3
4
5
6
7
8
9
|
var
f = (
function
(){
var
a = 1;
return
function
(){
alert(a++);
}
})();
f();
//彈出1
f();
//彈出2其內部的a並沒有清空。
|
上面就是匿名函數版,創建的時候就調用一次。
五、閉包的作用
1、減少全局變量
通過上面的了解我們知道,閉包能夠將局部變量封裝永久局部變量,函數調用完畢后依然存在。它能夠令一個局部變量永久存在,如數組,自定義的哈希表對象等。封裝到局部變量能夠減少全局變量,減少被覆蓋的可能性。
2、延長局部變量壽命
這點沒辦法解釋了。
參考:javascript閉包