1. 概念
- 閉包是指有權訪問另一個函數作用域中變量的函數
- 創建閉包的最常見的方式就是在一個函數內創建另一個函數,當內部函數被保存到外部時,將會生成閉包。
- 閉包會導致原有作用域鏈不釋放,造成內存泄漏
- 通過另一個函數訪問這個函數的局部變量,利用閉包可以突破作用鏈域,將函數內部的變量和方法傳遞到外部。
2. 閉包的特性
- 函數內再嵌套函數
- 內部函數可以引用外層的參數和變量
- .參數和變量不會被垃圾回收機制回收
function a(){
function b(){
console.log(aaa);//123
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();
3. 作用
4. 立即執行函數 (主要針對初始化功能的函數)
此類函數沒有聲明,在一次執行過後即釋放,適合做初始化工作。
var num = (function(a,b){
return a + b
}(1,2))
console.log(num);//3
注意:只有表達式才能被執行符號執行,例:
function a(){
console.log(123);//報錯 Uncaught SyntaxError: Unexpected token
}()
function a(){
console.log(123);//不報錯也不執行
}(1)//穿參的話
var a = function(){
console.log(123);//123
}()
console.log(a);//undefined,此時函數名將被忽略了
var x= 1;
if(function f(){}){//()爲執行符號,執行完函數就銷燬了,所以typeof f爲undefined
x += typeof f;
}
console.log(x);//1undefined
5. 經典案例
案例1:
function test(){
var arr = [];
for(var i = 0;i < 10;i++){
arr[i] = function(){//每次循環的時候=的前面依次變成arr[0],arr[1]...arr[9],後面是定義的一個函數,但是沒執行,所以裏面一直都是console.log(i)
console.log(i)
}
}
return arr
}
var myArr = test();
for(var j = 0;j < myArr.length;j++){
myArr[j]();//到了此處,上面的函數纔開始執行,而這時候上面的for循環已經結束,退出循環後i變成了10,所以頁面打印出來10次10.
}
如果想輸出0,1,2,3,4,5,6,7,8,9,解決辦法爲:
//方法一:利用函數自執行
function test(){
var arr = [];
for(var i = 0;i < 10;i++){
(function(j){
arr[j] = function(){
console.log(j)
}
})(i)
}
return arr
}
var myArr = test();
for(j = 0;j < myArr.length;j++){
myArr[j]();
}
//方法:ES6中的let
function test(){
var arr = [];
for(let i = 0;i < 10;i++){
arr[i] = function(){
console.log(i)
}
}
return arr
}
var myArr = test();
for(var j = 0;j < myArr.length;j++){
myArr[j]();
}
案例2:不依賴外部變量實現累加器效果
//傳統方法依賴外部變量實現累加器效果
var num = 0;
function a(){
num++;
console.log(num);
}
a();//1
a();//2
//不依賴外部變量實現累加器效果
function a(){
var num = 0;
function b(){
num++;
console.log(num);
}
return b;
}
var demo = a();
demo();//1
demo();//2