สรุปJavascript ปิดอนุญาตให้มีฟังก์ชั่นการเข้าถึงตัวแปรที่ประกาศไว้ในฟังก์ชั่นคำศัพท์ผู้ปกครอง
ลองดูคำอธิบายโดยละเอียดเพิ่มเติม เพื่อให้เข้าใจถึงการปิดเป็นสิ่งสำคัญที่จะต้องเข้าใจว่า JavaScript กำหนดขอบเขตตัวแปรอย่างไร
ขอบเขต
ในขอบเขต JavaScript ถูกกำหนดด้วยฟังก์ชัน ทุกฟังก์ชั่นจะกำหนดขอบเขตใหม่
ลองพิจารณาตัวอย่างต่อไปนี้
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 พิมพ์
hello
hello
2
Am I Accessible?
ตอนนี้ขอให้พิจารณากรณีที่เราได้ฟังก์ชั่นที่กำหนดไว้ในฟังก์ชั่นอื่นg
f
function f()
{//begin of scope f
function g()
{//being of scope g
/*...*/
}//end of scope g
/*...*/
}//end of scope f
เราจะเรียกปกครองศัพท์ของ ตามที่อธิบายไว้ก่อนหน้านี้เรามี 2 ขอบเขต; ขอบเขตและขอบเขตf
g
f
g
แต่ขอบเขตหนึ่งคือ "ภายใน" ขอบเขตอื่นดังนั้นขอบเขตของฟังก์ชันลูกเป็นส่วนหนึ่งของขอบเขตของฟังก์ชันหลักหรือไม่ เกิดอะไรขึ้นกับตัวแปรที่ประกาศในขอบเขตของฟังก์ชันพาเรนต์ ฉันจะสามารถเข้าถึงพวกเขาจากขอบเขตของฟังก์ชันลูกได้หรือไม่ นั่นคือสิ่งที่ขั้นตอนการปิด
ปิด
ใน JavaScript ฟังก์ชั่นg
ไม่เพียง แต่สามารถเข้าถึงตัวแปรใด ๆ ที่ประกาศในขอบเขตg
แต่ยังเข้าถึงตัวแปรใด ๆ f
ที่ประกาศในขอบเขตของฟังก์ชั่นแม่
พิจารณาดังนี้
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 พิมพ์
hello
undefined
ดู Let 's console.log(foo);
ที่บรรทัด ณ จุดนี้เราอยู่ในขอบเขตg
และเราพยายามที่จะเข้าถึงตัวแปรที่ประกาศอยู่ในขอบเขตfoo
f
แต่ตามที่ระบุไว้ก่อนที่เราจะสามารถเข้าถึงตัวแปรใด ๆ ที่ประกาศในฟังก์ชั่นผู้ปกครองศัพท์ซึ่งเป็นกรณีที่นี่; เป็นผู้ปกครองของคำศัพท์g
f
ดังนั้นhello
จะถูกพิมพ์ ตอนนี้ขอให้ดูที่บรรทัด
console.log(bar);
ณ จุดนี้เราอยู่ในขอบเขตf
และเราพยายามที่จะเข้าถึงตัวแปรที่ประกาศอยู่ในขอบเขตbar
ไม่ได้ประกาศในขอบเขตปัจจุบันและฟังก์ชั่นไม่ได้เป็นพาเรนต์ของดังนั้นจึงไม่ได้กำหนดg
bar
g
f
bar
ที่จริงแล้วเราสามารถเข้าถึงตัวแปรที่ประกาศในขอบเขตของฟังก์ชัน "ผู้ปกครองหลัก" ศัพท์ ดังนั้นหากจะมีฟังก์ชั่นที่h
กำหนดไว้ภายในฟังก์ชั่นg
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
แล้วh
จะสามารถเข้าถึงตัวแปรทั้งหมดที่ประกาศในขอบเขตของฟังก์ชั่นh
, และg
f
นี้จะกระทำด้วยการปิด ในการปิด JavaScript ช่วยให้เราสามารถเข้าถึงตัวแปรใด ๆ ที่ประกาศในฟังก์ชั่นผู้ปกครองศัพท์, ในฟังก์ชั่นผู้ปกครองระดับสูง, ในฟังก์ชั่นผู้ปกครองระดับสูงศัพท์ ฯลฯ นี้สามารถมองเห็นเป็นห่วงโซ่ขอบเขต ; scope of current function -> scope of lexical parent function -> scope of lexical grand parent function -> ...
จนกระทั่งฟังก์ชันพาเรนต์สุดท้ายที่ไม่มีพาเรนต์ศัพท์
วัตถุหน้าต่าง
อันที่จริงเชนไม่ได้หยุดที่ฟังก์ชันพาเรนต์สุดท้าย มีขอบเขตพิเศษอีกหนึ่งข้อ ขอบเขตทั่วโลก ทุกตัวแปรที่ไม่ได้ประกาศในฟังก์ชั่นนั้นจะถูกประกาศให้อยู่ในขอบเขตส่วนกลาง ขอบเขตทั่วโลกมีความเชี่ยวชาญสองประการ
- ทุกตัวแปรที่ประกาศในขอบเขตทั่วโลกสามารถเข้าถึงได้ทุกที่
- ตัวแปรที่ประกาศในขอบเขตทั่วโลกสอดคล้องกับคุณสมบัติของ
window
วัตถุ
ดังนั้นจึงมีสองวิธีในการประกาศตัวแปรfoo
ในขอบเขตส่วนกลาง โดยไม่ได้ประกาศในฟังก์ชั่นหรือโดยการตั้งค่าคุณสมบัติfoo
ของวัตถุหน้าต่าง
ทั้งสองพยายามใช้การปิด
ตอนนี้คุณได้อ่านคำอธิบายโดยละเอียดแล้วตอนนี้อาจเห็นได้ชัดว่าโซลูชันทั้งสองใช้การปิด แต่เพื่อให้แน่ใจว่ามาพิสูจน์กัน
มาสร้างภาษาโปรแกรมใหม่กันเถอะ; ใช้ JavaScript ไม่มีปิด ตามชื่อที่แนะนำ JavaScript-No-Off จะเหมือนกับ JavaScript ยกเว้นว่าจะไม่รองรับการปิด
กล่าวอีกนัยหนึ่ง;
var foo = 'hello';
function f(){console.log(foo)};
f();
//JavaScript-No-Closure prints undefined
//JavaSript prints hello
เอาล่ะเรามาดูกันว่าเกิดอะไรขึ้นกับโซลูชั่นแรกด้วย JavaScript-No-Off
for(var i = 0; i < 10; i++) {
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2); //i2 is undefined in JavaScript-No-Closure
}, 1000)
})();
}
ดังนั้นสิ่งนี้จะพิมพ์undefined
10 ครั้งใน JavaScript-No-Off
ดังนั้นทางออกแรกใช้การปิด
ลองดูวิธีแก้ปัญหาที่สอง;
for(var i = 0; i < 10; i++) {
setTimeout((function(i2){
return function() {
console.log(i2); //i2 is undefined in JavaScript-No-Closure
}
})(i), 1000);
}
ดังนั้นสิ่งนี้จะพิมพ์undefined
10 ครั้งใน JavaScript-No-Off
โซลูชันทั้งสองใช้การปิด
แก้ไข: สันนิษฐานว่าตัวอย่างโค้ด 3 ตัวนี้ไม่ได้กำหนดไว้ในขอบเขตส่วนกลาง มิฉะนั้นตัวแปรfoo
และi
จะผูกกับwindow
วัตถุและสามารถเข้าถึงได้ผ่านwindow
วัตถุทั้งใน JavaScript และ JavaScript-No-Off