Özetle JavaScript Closures bir fonksiyonu sağlayan erişim bir değişkeni olan bir sözcük ebeveynli fonksiyonunda ilan .
Daha ayrıntılı bir açıklama görelim. Kapanışları anlamak için JavaScript'in değişkenleri nasıl kapsadığını anlamak önemlidir.
kapsamları
JavaScript'te kapsamlar işlevlerle tanımlanır. Her işlev yeni bir kapsam tanımlar.
Aşağıdaki örneği ele alalım;
function f()
{//begin of scope f
var foo='hello'; //foo is declared in scope f
for(var i=0;i<2;i++){//i is declared in scope f
//the for loop is not a function, therefore we are still in scope f
var bar = 'Am I accessible?';//bar is declared in scope f
console.log(foo);
}
console.log(i);
console.log(bar);
}//end of scope f
f baskı çağrı
hello
hello
2
Am I Accessible?
Şimdi g
başka bir fonksiyonda tanımlanmış bir fonksiyonumuz olduğunu düşünelim f
.
function f()
{//begin of scope f
function g()
{//being of scope g
/*...*/
}//end of scope g
/*...*/
}//end of scope f
Biz arayacak sözcük ebeveyne ait . Daha önce açıklandığı gibi, şimdi 2 kapsamımız var; kapsam ve kapsam .f
g
f
g
Ancak bir kapsam diğer kapsamda "kapsamdadır", bu nedenle child fonksiyonunun kapsamı, ana fonksiyonun kapsamının bir parçası mıdır? Üst işlev kapsamında açıklanan değişkenlerle ne olur; bunlara çocuk işlevi kapsamından erişebilecek miyim? Tam olarak kapanışlar devreye giriyor.
Kapaklar
JavaScript'te işlev g
yalnızca kapsamda bildirilen değişkenlere g
değil, üst işlev kapsamında bildirilen değişkenlere de erişebilir f
.
Aşağıdakileri düşünün;
function f()//lexical parent function
{//begin of scope f
var foo='hello'; //foo declared in scope f
function g()
{//being of scope g
var bar='bla'; //bar declared in scope g
console.log(foo);
}//end of scope g
g();
console.log(bar);
}//end of scope f
f baskı çağrı
hello
undefined
Çizgiye bakalım console.log(foo);
. Bu noktada kapsamdayız g
ve foo
kapsamda bildirilen değişkene erişmeye çalışıyoruz f
. Ancak daha önce de belirtildiği gibi, burada söz konusu olan sözcüksel bir üst işlevde bildirilen herhangi bir değişkene erişebiliriz; g
sözlü ebeveynidir f
. Bu nedenle hello
yazdırılır.
Şimdi çizgiye bakalım console.log(bar);
. Bu noktada kapsamdayız f
ve bar
kapsamda bildirilen değişkene erişmeye çalışıyoruz g
. bar
geçerli kapsamda bildirilmez ve işlev g
üst öğesi değildir f
, bu nedenle bar
tanımsızdır
Aslında, sözcüksel "büyük ebeveyn" işlevi kapsamında bildirilen değişkenlere de erişebiliriz. Bu nedenle h
, işlev içinde tanımlanmış bir işlev varsag
function f()
{//begin of scope f
function g()
{//being of scope g
function h()
{//being of scope h
/*...*/
}//end of scope h
/*...*/
}//end of scope g
/*...*/
}//end of scope f
Daha sonra h
fonksiyonun kapsamda bildirilen tüm değişkenleri erişmek mümkün olacağını h
, g
ve f
. Bu kapaklarla yapılır . JavaScript içinde kapakları Bu olarak görülebilir vb sözcük büyük-bin ana fonksiyonu, içinde, sözcük büyük ana işlevi, sözcük üst işlevi bildirilen herhangi bir değişken erişmek olanak sağlıyor kapsam zinciri ; scope of current function -> scope of lexical parent function -> scope of lexical grand parent function -> ...
sözcüksel ebeveyni olmayan son ana işleve kadar.
Pencere nesnesi
Aslında zincir son ana işlevde durmaz. Bir tane daha özel kapsam var; Küresel kapsamı . Bir işlevde bildirilmeyen her değişkenin küresel kapsamda bildirildiği kabul edilir. Küresel kapsam iki özelliğe sahiptir;
- Genel kapsamda bildirilen her değişken erişilebilir her yerde
- genel kapsamda bildirilen değişkenler
window
nesnenin özelliklerine karşılık gelir .
Bu nedenle foo
, küresel kapsamda bir değişken bildirmenin tam olarak iki yolu vardır ; ya bir işlevde bildirmeyerek ya foo
da pencere nesnesinin özelliğini ayarlayarak .
Her iki deneme de kapanışları kullanıyor
Şimdi daha ayrıntılı bir açıklama okuduğunuza göre, artık her iki çözümün de kapanışları kullandığı görülebilir. Ama emin olmak için bir kanıt yapalım.
Yeni bir Programlama Dili oluşturalım; JavaScript No-Kapanış. Adından da anlaşılacağı gibi, JavaScript-No-Closure, Kapanışları desteklemediği için JavaScript ile aynıdır.
Başka bir deyişle;
var foo = 'hello';
function f(){console.log(foo)};
f();
//JavaScript-No-Closure prints undefined
//JavaSript prints hello
Tamam, JavaScript-No-Closure ile ilk çözümde neler olduğunu görelim;
for(var i = 0; i < 10; i++) {
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2); //i2 is undefined in JavaScript-No-Closure
}, 1000)
})();
}
bu nedenle bu yazdırılacaktır undefined
, JavaScript-No-Closure'da 10 kez .
Bu nedenle ilk çözüm kapama kullanır.
İkinci çözüme bakalım;
for(var i = 0; i < 10; i++) {
setTimeout((function(i2){
return function() {
console.log(i2); //i2 is undefined in JavaScript-No-Closure
}
})(i), 1000);
}
bu nedenle bu yazdırılacaktır undefined
, JavaScript-No-Closure'da 10 kez .
Her iki çözüm de kapanış kullanır.
Düzenleme: Bu 3 kod parçacıklarının genel kapsamda tanımlanmadığı varsayılır. Aksi takdirde, değişkenler foo
ve nesneye i
bağlanır window
ve bu nedenle window
hem JavaScript hem de JavaScript-No-Closure içindeki nesne aracılığıyla erişilebilir .