理解閉包三個基本的事實
第一個事實:js允許你引用在當前函數以外定義的變量。
function makeSandwich(){
var magicIngredient=”peanut butter”;
function make(filling){
return magicIngredient+’and ’+filling;
}
return make(‘jelly’);
}
makeSandwich();//”peanut butter and jelly”
圖上直接指出如下
第二個事實:即使外部函數已經返回,當前函數仍然可以引用在外部函數所定義的變量。
function sandwichMaker(){
var magicIngredient=”peanut butter”;
function make(filling){
return magicIngredient+’and ’+filling;
}
return make;
}
var f=sandwichMaker();
f(“jelly”);//”peanut butter and jelly”
f(“bananas”);//”peanut butter and bananas”
f(“marshmallows”);//”peanut butter and marshmallows”
還是上圖標識
原理:js的函數值包含了比調用它們時執行所需要的代碼還要多的信息。而且js函數值還在內部存儲它們可能會引用的定義在其封閉作用域的變量。那些在其所涵蓋的作用域內跟蹤變量的函數被稱為閉包。make函數就是一個閉包。其代碼引用了兩個外部變量:magicIngredient和filling。每當make被調用時,其代碼都能引用到這兩個變量,因為該閉包存儲了這兩個變量。
函數可以引用在其作用域內的任何變量,包括參數和外部函數變量。
function sandwichMaker(magicIngredient){
function make(filling){
return magicIngredient+”and ”+filling;
}
return make;
}
var hamAnd=sandwichMaker(“ham”);
hamAnd(“cheese”);//”ham and cheese”
hamAnd(“mustard”);//”ham and mustard”
var turkeyAnd=sandwichMaker(“trukey”);
turkeyAnd(“Swiss”);//”trukey and Swiss”
turkeyAnd(“Provolone”);//”trukey and Provolone”
閉包是js最優雅、最有表現力的特性之一,也是許多慣用法的核心。js還提供了一種更為方便構建閉包的字面量語法--函數表達式。
function sandwichMaker(magicIngredient){
return function(filling){
return magicIngredient+”and ”+filling;
}
}
請注意,該函數表達式是匿名的。由於只需要產生一個新值,而不需要在局部使用,所以沒必要給該函數命名。
第三個事實:閉包可以更新外部變量的值。
實際上,閉包存儲的是外部變量的引用,而不是它們的值的副本。因此任何具在訪問這些外部變量的閉包,都可以進行更新。
function box(){
var val=undefined;
return {
set:function(newVal){val=newVal},
get:function(){return val},
type:function(){return typeof val}
}
}
var b=box();
b.type();//”undefined”
b.set(98.6);
b.get();//98.6
b.type();//”number”
這個例子里產生了一個包含三個閉包的對象。這三個閉包是set,get和type屬性。它們共享訪問val變量。
提示
- 函數可以引用定義在其外部作用域的變量
- 閉包比創建它們的函數有更長的生命周期
- 閉包在內部存儲其外部變量的引用,並能讀寫這些變量
后記
這個部分,這覺得這里講得已經很清楚,如果想再深入去了解,可以去看高3上面關於閉包的講解。
里面對作用域鏈,執行環境,變量對象,都有詳細說明。