ขอบเขตของตัวแปรในจาวาสคริปต์คืออะไร? พวกเขามีขอบเขตเดียวกันภายในเมื่อเทียบกับฟังก์ชั่นภายนอกหรือไม่? หรือว่ามันสำคัญ นอกจากนี้ยังมีการจัดเก็บตัวแปรหากพวกเขาถูกกำหนดทั่วโลก?
ขอบเขตของตัวแปรในจาวาสคริปต์คืออะไร? พวกเขามีขอบเขตเดียวกันภายในเมื่อเทียบกับฟังก์ชั่นภายนอกหรือไม่? หรือว่ามันสำคัญ นอกจากนี้ยังมีการจัดเก็บตัวแปรหากพวกเขาถูกกำหนดทั่วโลก?
คำตอบ:
JavaScript มีการกำหนดขอบเขตและคำศัพท์ (หรือที่เรียกว่าแบบคงที่) ซึ่งหมายความว่าคุณสามารถบอกขอบเขตของตัวระบุได้โดยดูที่ซอร์สโค้ด
สี่ขอบเขตคือ:
นอกเหนือจากกรณีพิเศษของขอบเขตโกลบอลและโมดูลตัวแปรจะถูกประกาศโดยใช้var
(ขอบเขตฟังก์ชั่น), let
(ขอบเขตบล็อก) และconst
(ขอบเขตบล็อก) การประกาศตัวระบุรูปแบบอื่น ๆ ส่วนใหญ่มีขอบเขตบล็อกในโหมดเข้มงวด
ขอบเขตคือขอบเขตของ codebase ซึ่งตัวระบุนั้นถูกต้อง
สภาพแวดล้อมศัพท์คือการทำแผนที่ระหว่างชื่อตัวระบุและค่าที่เกี่ยวข้องกับพวกเขา
ขอบเขตถูกสร้างขึ้นจากการซ้อนการลิงก์ของสภาวะแวดล้อมคำศัพท์โดยแต่ละระดับในการซ้อนจะสอดคล้องกับสภาวะแวดล้อมคำศัพท์ของบริบทการดำเนินการบรรพบุรุษ
สภาพแวดล้อมศัพท์ที่เชื่อมโยงเหล่านี้สร้างขอบเขต "โซ่" ความละเอียดของตัวระบุเป็นกระบวนการค้นหาตามสายโซ่นี้เพื่อหาตัวระบุที่ตรงกัน
ความละเอียดของตัวระบุจะเกิดขึ้นในทิศทางเดียวเท่านั้น: ออกไปด้านนอก ด้วยวิธีนี้สภาวะแวดล้อมคำศัพท์ภายนอกไม่สามารถ "เห็น" ในสภาวะแวดล้อมคำศัพท์ภายใน
มีปัจจัยที่เกี่ยวข้องสามประการในการตัดสินใจขอบเขตของตัวระบุใน JavaScript:
สามารถประกาศตัวระบุวิธีได้บางวิธี:
var
, let
และconst
var
ในโหมดที่ไม่เข้มงวด)import
งบeval
ตัวระบุตำแหน่งบางตัวสามารถประกาศได้:
ตัวระบุที่ประกาศโดยใช้var
มีขอบเขตฟังก์ชั่นนอกเหนือจากเมื่อมีการประกาศโดยตรงในบริบทโลกซึ่งในกรณีนี้พวกเขาจะถูกเพิ่มเป็นคุณสมบัติในวัตถุทั่วโลกและมีขอบเขตทั่วโลก มีกฎแยกต่างหากสำหรับการใช้งานในeval
ฟังก์ชั่น
ตัวระบุที่ประกาศใช้let
และconst
มีขอบเขตบล็อกนอกเหนือจากเมื่อมีการประกาศโดยตรงในบริบทส่วนกลางซึ่งในกรณีนี้จะมีขอบเขตทั่วโลก
หมายเหตุ: การlet
, const
และยกทั้งหมดvar
ซึ่งหมายความว่าตำแหน่งเชิงตรรกะของการกำหนดความหมายคือด้านบนของขอบเขตการปิดล้อม (บล็อกหรือฟังก์ชัน) อย่างไรก็ตามตัวแปรที่ประกาศใช้let
และconst
ไม่สามารถอ่านหรือกำหนดให้จนกว่าการควบคุมจะผ่านจุดประกาศในซอร์สโค้ด ช่วงเวลาระหว่างกาลเป็นที่รู้จักกันในชื่อเขตตายชั่วคราว
function f() {
function g() {
console.log(x)
}
let x = 1
g()
}
f() // 1 because x is hoisted even though declared with `let`!
ชื่อพารามิเตอร์ฟังก์ชั่นจะถูกกำหนดขอบเขตให้กับร่างกายของฟังก์ชั่น โปรดทราบว่ามีความซับซ้อนเล็กน้อยในเรื่องนี้ ฟังก์ชั่นที่ประกาศเป็นอาร์กิวเมนต์เริ่มต้นจะปิดรายการพารามิเตอร์ไม่ใช่ส่วนของฟังก์ชัน
การประกาศฟังก์ชั่นมีขอบเขตบล็อกในโหมดเข้มงวดและขอบเขตฟังก์ชันในโหมดไม่เข้มงวด หมายเหตุ: โหมดที่ไม่เข้มงวดเป็นชุดที่ซับซ้อนของกฎฉุกเฉินตามการใช้งานทางประวัติศาสตร์ที่แปลกประหลาดของเบราว์เซอร์ที่แตกต่างกัน
นิพจน์ฟังก์ชันที่ระบุชื่อจะถูกกำหนดขอบเขตให้กับตัวเอง (เช่นเพื่อการเรียกซ้ำ)
ในโหมดที่ไม่เข้มงวดคุณสมบัติที่กำหนดโดยปริยายบนวัตถุโกลบอลจะมีขอบเขตส่วนกลางเนื่องจากวัตถุทั่วโลกอยู่ที่ด้านบนของห่วงโซ่ขอบเขต ในโหมดเข้มงวดไม่อนุญาตให้ใช้
ในeval
สตริงตัวแปรที่ประกาศโดยใช้var
จะถูกวางไว้ในขอบเขตปัจจุบันหรือหากeval
มีการใช้โดยอ้อมเป็นคุณสมบัติในวัตถุทั่วโลก
ต่อไปนี้จะโยน ReferenceError เนื่องจากชื่อที่x
, y
และไม่มีนอกหมายของฟังก์ชั่นz
f
function f() {
var x = 1
let y = 1
const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)
ต่อไปนี้จะโยน ReferenceError สำหรับy
และz
, แต่ไม่ใช่x
เพราะ, การมองเห็นของx
ไม่ถูก จำกัด โดยบล็อก บล็อกที่กำหนดร่างของโครงสร้างการควบคุมเช่นif
, for
และwhile
ประพฤติในทำนองเดียวกัน
{
var x = 1
let y = 1
const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope
ในต่อไปx
นี้สามารถมองเห็นได้นอกวงเนื่องจากvar
มีขอบเขตฟังก์ชั่น:
for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)
... เนื่องจากพฤติกรรมนี้คุณต้องระวังเกี่ยวกับการปิดตัวแปรที่ประกาศใช้var
ในลูป มีเพียงหนึ่งอินสแตนซ์ของตัวแปรที่x
ประกาศที่นี่และมันตั้งอยู่นอกตรรกะของลูป
พิมพ์ต่อไปนี้5
ห้าครั้งแล้วพิมพ์5
เป็นครั้งที่หกสำหรับconsole.log
วงนอก:
for(var x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop
งานพิมพ์ต่อไปนี้undefined
เนื่องจากx
ถูกบล็อกขอบเขต การเรียกกลับถูกเรียกใช้ทีละอะซิงโครนัส พฤติกรรมใหม่สำหรับlet
ตัวแปรหมายความว่าแต่ละฟังก์ชั่นที่ไม่ระบุชื่อปิดมากกว่าตัวแปรที่แตกต่างกันชื่อx
(เหมือนมันจะได้ทำกับvar
) และจำนวนเต็ม0
ผ่าน4
จะถูกพิมพ์ .:
for(let x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined
ต่อไปนี้จะไม่ส่งต่อReferenceError
เนื่องจากการแสดงผลของx
บล็อกไม่ถูก จำกัด มันจะอย่างไรก็ตามพิมพ์undefined
เพราะตัวแปรยังไม่ได้เริ่มต้น (เพราะif
คำสั่ง)
if(false) {
var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised
ตัวแปรที่ประกาศที่ด้านบนของfor
ลูปที่ใช้let
จะถูกกำหนดขอบเขตไว้ที่เนื้อความของลูป:
for(let x = 0; x < 10; ++x) {}
console.log(typeof x) // undefined, because `x` is block-scoped
ต่อไปนี้จะโยนReferenceError
เนื่องจากการเปิดเผยx
ถูก จำกัด โดยบล็อก:
if(false) {
let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped
ตัวแปรที่ประกาศใช้var
, let
หรือconst
ทุกขอบเขตโมดูล:
// module1.js
var x = 0
export function f() {}
//module2.js
import f from 'module1.js'
console.log(x) // throws ReferenceError
ต่อไปนี้จะประกาศคุณสมบัติบนวัตถุส่วนกลางเนื่องจากตัวแปรที่ประกาศใช้var
ภายในบริบทส่วนกลางจะถูกเพิ่มเป็นคุณสมบัติให้กับวัตถุทั่วโลก:
var x = 1
console.log(window.hasOwnProperty('x')) // true
let
และconst
ในบริบทโลกไม่ได้เพิ่มคุณสมบัติให้กับวัตถุทั่วโลก แต่ยังคงมีขอบเขตทั่วโลก:
let x = 1
console.log(window.hasOwnProperty('x')) // false
สามารถพิจารณาพารามิเตอร์ของฟังก์ชั่นที่จะประกาศในฟังก์ชั่นร่างกาย:
function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function
พารามิเตอร์ catch block ถูกกำหนดขอบเขตไว้ที่เนื้อหา catch-block:
try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block
นิพจน์ฟังก์ชันที่มีชื่อถูกกำหนดขอบเขตเฉพาะนิพจน์เท่านั้น:
(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression
ในโหมดที่ไม่เข้มงวดคุณสมบัติที่กำหนดโดยปริยายบนอ็อบเจ็กต์โกลบอลจะถูกกำหนดขอบเขตแบบโกลบอล ในโหมดเข้มงวดคุณได้รับข้อผิดพลาด
x = 1 // implicitly defined property on the global object (no "var"!)
console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true
ในโหมดที่ไม่เข้มงวดการประกาศฟังก์ชันมีขอบเขตฟังก์ชัน ในโหมดเข้มงวดพวกเขามีขอบเขตบล็อก
'use strict'
{
function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped
ขอบเขตถูกกำหนดให้เป็นขอบเขตศัพท์ของรหัสซึ่งตัวระบุนั้นถูกต้อง
ใน JavaScript ทุกฟังก์ชั่นวัตถุมีการ[[Environment]]
อ้างอิงที่ซ่อนอยู่ซึ่งเป็นการอ้างอิงถึงสภาพแวดล้อมศัพท์ของบริบทการดำเนินการ (กรอบสแต็ก) ที่มันถูกสร้างขึ้น
เมื่อคุณเรียกใช้ฟังก์ชั่น[[Call]]
วิธีการที่ซ่อนอยู่จะถูกเรียก วิธีนี้จะสร้างบริบทการดำเนินการใหม่และสร้างการเชื่อมโยงระหว่างบริบทการดำเนินการใหม่และสภาพแวดล้อมคำศัพท์ของฟังก์ชั่น - วัตถุ มันทำได้โดยการคัดลอก[[Environment]]
ค่าในฟังก์ชั่นวัตถุไปยังเขตข้อมูลอ้างอิงด้านนอกบนสภาพแวดล้อมศัพท์ของบริบทการดำเนินการใหม่
โปรดทราบว่าการเชื่อมโยงระหว่างการดำเนินการบริบทใหม่และสภาพแวดล้อมคำศัพท์ของวัตถุฟังก์ชั่นนี้เรียกว่าปิด
ดังนั้นใน JavaScript ขอบเขตจะถูกนำไปใช้ผ่านสภาพแวดล้อมของคำศัพท์ที่เชื่อมโยงเข้าด้วยกันใน "chain" โดยการอ้างอิงภายนอก สายโซ่ของสภาพแวดล้อมทางศัพท์นี้เรียกว่าขอบเขตลูกโซ่และการจำแนกตัวระบุเกิดขึ้นโดยการค้นหาสายโซ่เพื่อหาตัวระบุที่ตรงกัน
Javascript ใช้กลุ่มขอบเขตเพื่อสร้างขอบเขตสำหรับฟังก์ชันที่กำหนด โดยทั่วไปจะมีหนึ่งขอบเขตส่วนกลางและแต่ละฟังก์ชันที่กำหนดมีขอบเขตซ้อนกันของตัวเอง ฟังก์ชั่นใด ๆ ที่กำหนดไว้ในฟังก์ชั่นอื่นมีขอบเขตท้องถิ่นซึ่งเชื่อมโยงกับฟังก์ชั่นด้านนอก มันมักจะเป็นตำแหน่งในแหล่งที่มาที่กำหนดขอบเขต
องค์ประกอบในห่วงโซ่ขอบเขตนั้นโดยทั่วไปแล้วแผนที่ที่มีตัวชี้ไปยังขอบเขตหลัก
เมื่อแก้ไขตัวแปรจาวาสคริปต์จะเริ่มที่ขอบเขตด้านในสุดแล้วค้นหาออกมา
ตัวแปรที่ประกาศทั่วโลกมีขอบเขตทั่วโลก ตัวแปรที่ประกาศภายในฟังก์ชันนั้นถูกกำหนดขอบเขตไว้ที่ฟังก์ชันนั้นและตัวแปรโกลบอลเงาที่มีชื่อเดียวกัน
(ฉันแน่ใจว่ามีรายละเอียดปลีกย่อยมากมายที่โปรแกรมเมอร์ JavaScript จริง ๆ จะสามารถชี้ให้เห็นคำตอบอื่น ๆ ได้โดยเฉพาะฉันมาที่หน้านี้เกี่ยวกับความthis
หมายที่แท้จริงได้ตลอดเวลาหวังว่าลิงก์แนะนำเพิ่มเติมนี้จะเพียงพอสำหรับคุณ .)
ตามเนื้อผ้าจาวาสคริปต์มีขอบเขตสองประเภทเท่านั้น:
ฉันจะไม่ทำอย่างละเอียดในเรื่องนี้เนื่องจากมีคำตอบอื่น ๆ อีกมากมายที่อธิบายถึงความแตกต่าง
รายละเอียด JavaScript ล่าสุดตอนนี้ยังอนุญาตให้มีขอบเขตที่สาม:
ตามเนื้อผ้าคุณสร้างตัวแปรของคุณเช่นนี้:
var myVariable = "Some text";
ตัวแปรขอบเขตบล็อกถูกสร้างขึ้นเช่นนี้:
let myVariable = "Some text";
เพื่อให้เข้าใจถึงความแตกต่างระหว่างขอบเขตการทำงานและขอบเขตบล็อกให้พิจารณารหัสต่อไปนี้:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
ที่นี่เราจะเห็นได้ว่าตัวแปรของเราj
เป็นที่รู้จักเฉพาะในลูปแรก แต่ไม่ใช่ก่อนและหลัง แต่ตัวแปรของเราi
เป็นที่รู้จักในทุกฟังก์ชั่น
นอกจากนี้ให้พิจารณาว่าตัวแปรที่กำหนดขอบเขตของบล็อกไม่เป็นที่รู้จักก่อนที่จะมีการประกาศเนื่องจากไม่ได้ยก นอกจากนี้คุณยังไม่ได้รับอนุญาตให้ประกาศตัวแปรที่กำหนดขอบเขตของบล็อกใหม่อีกครั้งภายในบล็อกเดียวกัน สิ่งนี้ทำให้เกิดข้อผิดพลาดน้อยกว่าตัวแปรตัวแปรที่กำหนดขอบเขตของบล็อกหรือตัวแปรที่กำหนดขอบเขตหน้าที่ซึ่งถูกยกขึ้นและไม่ก่อให้เกิดข้อผิดพลาดใด ๆ ในกรณีที่มีการประกาศหลายรายการ
ปลอดภัยหรือไม่ที่จะใช้วันนี้ขึ้นอยู่กับสภาพแวดล้อมของคุณ:
หากคุณกำลังเขียนโค้ด JavaScript ฝั่งเซิร์ฟเวอร์ ( Node.js ) คุณสามารถใช้let
คำสั่งนี้ได้อย่างปลอดภัย
หากคุณกำลังเขียนฝั่งไคลเอ็นต์รหัส JavaScript และใช้ transpiler เบราว์เซอร์ (เช่นTraceurหรือBabel-แบบสแตนด์อโลน ), คุณสามารถใช้let
คำสั่ง แต่รหัสของคุณมีแนวโน้มที่จะเป็นอะไรก็ได้ แต่ที่ดีที่สุดด้วยความเคารพต่อผลการดำเนินงาน
หากคุณกำลังเขียนโค้ด JavaScript ฝั่งไคลเอ็นต์และใช้ transpiler ที่ใช้ Node (เช่นสคริปต์เชลล์ traceurหรือBabel ) คุณสามารถใช้let
คำสั่งนี้ได้อย่างปลอดภัย และเนื่องจากเบราว์เซอร์ของคุณจะรู้เกี่ยวกับรหัส transpiled เท่านั้นข้อเสียของประสิทธิภาพจึงควร จำกัด
หากคุณกำลังเขียนโค้ด JavaScript ฝั่งไคลเอ็นต์และไม่ใช้ transpiler คุณต้องพิจารณาการสนับสนุนเบราว์เซอร์
นี่คือเบราว์เซอร์บางตัวที่ไม่รองรับlet
เลย:
สำหรับภาพรวมที่เป็นปัจจุบันซึ่งเบราว์เซอร์รองรับlet
คำสั่งในขณะที่คุณอ่านคำตอบนี้Can I Use
ดูหน้านี้
(*) ทั่วโลกและตัวแปรกำหนดขอบเขตหน้าที่สามารถเริ่มต้นได้และใช้งานก่อนที่จะมีการประกาศเพราะตัวแปร JavaScript ที่จะยก ซึ่งหมายความว่าการประกาศจะอยู่ด้านบนสุดของขอบเขตเสมอ
นี่คือตัวอย่าง:
<script>
var globalVariable = 7; //==window.globalVariable
function aGlobal( param ) { //==window.aGlobal();
//param is only accessible in this function
var scopedToFunction = {
//can't be accessed outside of this function
nested : 3 //accessible by: scopedToFunction.nested
};
anotherGlobal = {
//global because there's no `var`
};
}
</script>
คุณจะต้องการที่จะตรวจสอบการปิดและวิธีการใช้พวกเขาเพื่อให้สมาชิกส่วนตัว
กุญแจสำคัญที่ฉันเข้าใจคือ Javascript มีการกำหนดขอบเขตระดับฟังก์ชั่นเทียบกับการกำหนดขอบเขตบล็อก C ทั่วไป
ใน "Javascript 1.7" (ส่วนขยายของ Mozilla to Javascript) หนึ่งสามารถประกาศตัวแปรขอบเขตบล็อกด้วยlet
คำสั่ง :
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4
let
ไม่สนับสนุน
ความคิดในการกำหนดขอบเขตใน JavaScript เมื่อได้รับการออกแบบมาโดยเบรนแดนไอซ์มาจากHyperCardภาษาสคริปต์HyperTalk
ในภาษานี้จอแสดงผลได้ทำคล้ายกับการ์ดดัชนีสแต็ก มีมาสเตอร์การ์ดที่เรียกว่าพื้นหลัง มันโปร่งใสและสามารถมองเห็นเป็นการ์ดด้านล่าง เนื้อหาใด ๆ ในการ์ดฐานนี้ถูกแชร์กับการ์ดที่อยู่ด้านบน การ์ดแต่ละใบที่วางอยู่ด้านบนมีเนื้อหาของตัวเองซึ่งมีความสำคัญเหนือกว่าการ์ดก่อนหน้า แต่ยังคงสามารถเข้าถึงการ์ดก่อนหน้าได้หากต้องการ
นี่คือวิธีการออกแบบระบบกำหนดขอบเขต JavaScript มันมีชื่อแตกต่างกัน บัตรใน JavaScript เป็นที่รู้จักกันดำเนินบริบท ECMA แต่ละบริบทเหล่านี้มีสามส่วนหลัก สภาพแวดล้อมที่แปรปรวนสภาพแวดล้อมของคำศัพท์และการเชื่อมโยงนี้ กลับไปที่การอ้างอิงการ์ดสภาพแวดล้อมศัพท์ประกอบด้วยเนื้อหาทั้งหมดจากการ์ดก่อนหน้านี้ที่ต่ำกว่าในกอง บริบทปัจจุบันอยู่ที่ด้านบนสุดของสแต็กและเนื้อหาใด ๆ ที่ประกาศจะถูกเก็บไว้ในสภาพแวดล้อมแบบแปรผัน สภาพแวดล้อมของตัวแปรจะมีความสำคัญในกรณีของการชนกันของชื่อ
การรวมนี้จะชี้ไปที่วัตถุที่มี บางครั้งขอบเขตหรือบริบทการดำเนินการเปลี่ยนแปลงโดยไม่ต้องมีการเปลี่ยนแปลงวัตถุที่มีเช่นในฟังก์ชั่นที่ประกาศซึ่งวัตถุที่มีอาจจะเป็นwindow
หรือฟังก์ชั่นการสร้าง
บริบทการดำเนินการเหล่านี้สร้างขึ้นเมื่อใดก็ได้ที่มีการควบคุมการถ่ายโอน การควบคุมจะถูกถ่ายโอนเมื่อโค้ดเริ่มทำงานและสิ่งนี้กระทำได้จากการใช้งานฟังก์ชั่นเป็นหลัก
นั่นคือคำอธิบายทางเทคนิค ในทางปฏิบัติเป็นสิ่งสำคัญที่ต้องจำไว้ใน JavaScript
การใช้สิ่งนี้กับหนึ่งในตัวอย่างก่อนหน้านี้ (5. "การปิด") ในหน้านี้เป็นไปได้ที่จะทำตามสแต็คของบริบทการดำเนินการ ในตัวอย่างนี้มีสามบริบทในสแต็ก พวกเขาจะถูกกำหนดโดยบริบทด้านนอกบริบทในฟังก์ชั่นที่เรียกใช้ทันทีที่เรียกว่าโดย var หกและบริบทในฟังก์ชั่นกลับมาภายในของฟังก์ชั่นการเรียกใช้ทันทีของ var หก
i ) บริบทด้านนอก มันมีสภาพแวดล้อมที่แปรผันของ a = 1
ii ) บริบทของ IIFE มันมีสภาพแวดล้อมที่เป็นศัพท์ของ a = 1 แต่สภาพแวดล้อมของตัวแปรของ a = 6 ซึ่งมีความสำคัญใน stack
iii ) บริบทของฟังก์ชันที่ส่งคืนมันมีคำศัพท์ สภาพแวดล้อมของ = 6 และนั่นคือค่าอ้างอิงในการแจ้งเตือนเมื่อมีการเรียก
1) มีขอบเขตโกลบอลขอบเขตฟังก์ชันและขอบเขต with และ catch ไม่มีขอบเขตระดับ 'บล็อก' โดยทั่วไปสำหรับตัวแปร - คำสั่ง with และ catch จะเพิ่มชื่อให้กับบล็อก
2) ขอบเขตซ้อนกันโดยฟังก์ชั่นไปจนถึงขอบเขตทั่วโลก
3) คุณสมบัติได้รับการแก้ไขโดยการผ่านห่วงโซ่ต้นแบบ คำสั่ง with นำชื่อคุณสมบัติของวัตถุไว้ในขอบเขตคำศัพท์ที่กำหนดโดยบล็อกด้วย
แก้ไข: ECMAAScript 6 (Harmony) เป็น spec'ed เพื่อสนับสนุนการให้และฉันรู้ว่าโครเมี่ยมช่วยให้ธง 'สามัคคี' ดังนั้นบางทีมันอาจจะสนับสนุน ..
ให้เป็นการสนับสนุนสำหรับการกำหนดขอบเขตระดับบล็อก แต่คุณต้องใช้คำหลักเพื่อทำให้เกิดขึ้น
แก้ไข: ตามเบนจามินชี้ให้เห็นด้วยและจับงบในความคิดเห็นที่ฉันได้แก้ไขโพสต์และเพิ่มมากขึ้น ทั้งคำสั่ง with และ catch จะนำเสนอตัวแปรในบล็อกที่เกี่ยวข้องและนั่นคือขอบเขตบล็อก ตัวแปรเหล่านี้มีนามแฝงกับคุณสมบัติของวัตถุที่ส่งผ่านเข้ามา
//chrome (v8)
var a = { 'test1':'test1val' }
test1 // error not defined
with (a) { var test1 = 'replaced' }
test1 // undefined
a // a.test1 = 'replaced'
แก้ไข: ชี้แจงตัวอย่าง:
test1 ถูกกำหนดขอบเขตไว้ที่ with block แต่ถูกกำหนดเป็น a.test1 'Var test1' สร้างตัวแปรใหม่ test1 ในบริบทศัพท์ด้านบน (ฟังก์ชั่นหรือทั่วโลก) เว้นแต่จะเป็นคุณสมบัติของ a - ซึ่งมันเป็น
อ๊ะ! ระวังการใช้ 'กับ' - เช่นเดียวกับ var คือ noop หากตัวแปรถูกกำหนดไว้แล้วในฟังก์ชั่นมันยังเป็น noop ที่เกี่ยวข้องกับชื่อที่นำเข้าจากวัตถุ! ชื่อเล็ก ๆ น้อย ๆ ที่ขึ้นชื่อแล้วถูกกำหนดไว้จะทำให้ปลอดภัยกว่านี้มาก โดยส่วนตัวแล้วฉันจะไม่ใช้เพราะสิ่งนี้
with
คำสั่งเป็นรูปแบบของการกำหนดขอบเขตบล็อก แต่catch
คำสั่งเป็นรูปแบบที่พบมากขึ้น (ความเป็นจริงสนุก, การดำเนินการ v8 catch
มีwith
) - ที่สวยมากในรูปแบบเฉพาะของการกำหนดขอบเขตบล็อกใน JavaScript เอง (นั่นคือฟังก์ชั่นทั่วโลกลอง / จับ ด้วยและอนุพันธ์ของพวกเขา) แต่สภาพแวดล้อมโฮสต์มีความคิดที่แตกต่างกันของการกำหนดขอบเขต - ตัวอย่างเช่นเหตุการณ์แบบอินไลน์ในเบราว์เซอร์และโมดูล vm ของ NodeJS
ฉันพบว่าหลายคนที่เพิ่งเริ่มใช้ JavaScript มีปัญหาในการทำความเข้าใจว่าการสืบทอดนั้นพร้อมใช้งานในภาษาและขอบเขตการทำงานนั้นเป็นขอบเขตเดียวเท่านั้น ฉันให้ส่วนขยายแก่ beautifier ที่ฉันเขียนเมื่อปลายปีที่แล้วชื่อ JSPretty ขอบเขตคุณสมบัติของสีฟังก์ชันในรหัสและเชื่อมโยงสีกับตัวแปรทั้งหมดที่ประกาศในขอบเขตนั้นเสมอ การปิดจะแสดงให้เห็นด้วยสายตาเมื่อใช้ตัวแปรที่มีสีจากขอบเขตหนึ่งในขอบเขตที่แตกต่างกัน
ลองใช้คุณสมบัติได้ที่:
ดูตัวอย่างได้ที่:
ดูรหัสได้ที่:
ขณะนี้คุณลักษณะดังกล่าวรองรับการทำงานที่มีความลึกถึง 16 ฟังก์ชันซ้อนกัน แต่ในปัจจุบันไม่ได้เปลี่ยนสีของตัวแปรทั่วโลก
JavaScript มีขอบเขตสองประเภทเท่านั้น:
var
คำหลักมีขอบเขตการทำงานเมื่อใดก็ตามที่มีการเรียกใช้ฟังก์ชันวัตถุขอบเขตตัวแปรจะถูกสร้างขึ้น (และรวมอยู่ในห่วงโซ่ขอบเขต) ซึ่งตามด้วยตัวแปรใน JavaScript
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
ห่วงโซ่ขอบเขต ->
a
และouter
ฟังก์ชั่นอยู่ที่ระดับบนสุดในห่วงโซ่ขอบเขตvariable scope object
(และรวมอยู่ในห่วงโซ่ขอบเขต) เพิ่มด้วยตัวแปรb
ภายในตอนนี้เมื่อตัวแปรที่a
ต้องการมันเป็นครั้งแรกค้นหาขอบเขตตัวแปรที่ใกล้ที่สุดและถ้าตัวแปรไม่ได้มีมากกว่าที่จะย้ายไปยังวัตถุต่อไปของห่วงโซ่ขอบเขตตัวแปรซึ่งในกรณีนี้คือระดับหน้าต่าง
เพียงเพิ่มคำตอบอื่น ๆ ขอบเขตคือรายการค้นหาของตัวระบุที่ประกาศไว้ทั้งหมด (ตัวแปร) และบังคับใช้ชุดของกฎที่เข้มงวดเกี่ยวกับวิธีที่สิ่งเหล่านี้สามารถเข้าถึงได้ในการเรียกใช้โค้ดในปัจจุบัน การค้นหานี้อาจมีวัตถุประสงค์เพื่อกำหนดให้กับตัวแปรซึ่งเป็นข้อมูลอ้างอิง LHS (ด้านซ้าย) หรืออาจเป็นเพื่อวัตถุประสงค์ในการดึงค่าของมันซึ่งเป็นการอ้างอิง RHS (ด้านขวามือ) การค้นหาเหล่านี้เป็นสิ่งที่เอ็นจิ้น JavaScript ทำงานภายในเมื่อมีการรวบรวมและเรียกใช้โค้ด
ดังนั้นจากมุมมองนี้ฉันคิดว่ารูปภาพจะช่วยให้ฉันพบใน Scopes and Closures ebook ของ Kyle Simpson:
อ้างจาก ebook ของเขา:
สิ่งปลูกสร้างแสดงถึงชุดกฎขอบเขตที่ซ้อนกันของโปรแกรมของเรา ชั้นแรกของอาคารแสดงถึงขอบเขตการดำเนินการในปัจจุบันของคุณไม่ว่าคุณจะอยู่ที่ไหน ระดับสูงสุดของอาคารคือขอบเขตทั่วโลก คุณแก้ไขการอ้างอิง LHS และ RHS โดยดูจากชั้นปัจจุบันของคุณและหากคุณไม่พบมันให้ขึ้นลิฟต์ไปที่ชั้นถัดไปดูที่นั่นแล้วไปที่ชั้นถัดไปและอื่น ๆ เมื่อคุณไปถึงชั้นบนสุด (ขอบเขตทั่วโลก) คุณจะพบสิ่งที่คุณกำลังมองหาหรือไม่ แต่คุณต้องหยุดโดยไม่คำนึงถึง
สิ่งหนึ่งที่ควรทราบเมื่อพูดถึง "ขอบเขตการค้นหาหยุดเมื่อพบการแข่งขันครั้งแรก"
แนวคิดของ "ระดับขอบเขต" นี้อธิบายว่าเพราะเหตุใด "สิ่งนี้" จึงสามารถเปลี่ยนได้ด้วยขอบเขตที่สร้างขึ้นใหม่หากกำลังค้นหาในฟังก์ชันซ้อนกัน นี่คือลิงค์ที่จะกล่าวถึงรายละเอียดทั้งหมดเหล่านี้ทุกสิ่งที่คุณอยากรู้เกี่ยวกับขอบเขตของจาวาสคริปต์
เรียกใช้รหัส หวังว่านี่จะให้ความคิดเกี่ยวกับการกำหนดขอบเขต
Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
Name: 'object data',
f: function(){
alert(this.Name);
}
};
myObj.newFun = function(){
alert(this.Name);
}
function testFun(){
alert("Window Scope : " + window.Name +
"\nLocal Scope : " + Name +
"\nObject Scope : " + this.Name +
"\nCurrent document Scope : " + document.Name
);
}
testFun.call(myObj);
})(window,document);
ตัวแปรทั่วโลกเป็นเหมือนดาวทั่วโลก (Jackie Chan, Nelson Mandela) คุณสามารถเข้าถึงได้ (รับหรือตั้งค่า) จากส่วนใด ๆ ของแอปพลิเคชันของคุณ ฟังก์ชั่นทั่วโลกเป็นเหมือนเหตุการณ์ทั่วโลก (ปีใหม่คริสต์มาส) คุณสามารถดำเนินการ (โทร) พวกเขาจากส่วนใด ๆ ของใบสมัครของคุณ
//global variable
var a = 2;
//global function
function b(){
console.log(a); //access global variable
}
หากคุณอยู่ในสหรัฐอเมริกาคุณอาจรู้จัก Kim Kardashian ผู้มีชื่อเสียงที่น่าอับอาย แต่ผู้คนที่อยู่นอกสหรัฐอเมริกาจะไม่รู้จักเธอ เธอเป็นดาราท้องถิ่นที่ผูกพันกับดินแดนของเธอ
ตัวแปรท้องถิ่นเป็นเหมือนดาวท้องถิ่น คุณสามารถเข้าถึงได้ (รับหรือตั้งค่า) ภายในขอบเขต ฟังก์ชั่นในท้องถิ่นเป็นเหมือนเหตุการณ์ในท้องถิ่น - คุณสามารถดำเนินการเท่านั้น (เฉลิมฉลอง) ภายในขอบเขตนั้น หากคุณต้องการเข้าถึงพวกเขาจากนอกขอบเขตคุณจะได้รับข้อผิดพลาดอ้างอิง
function b(){
var d = 21; //local variable
console.log(d);
function dog(){ console.log(a); }
dog(); //execute local function
}
console.log(d); //ReferenceError: dddddd is not defined
มีขอบเขต JavaScript เกือบสองประเภทเท่านั้น:
ดังนั้นบล็อกใด ๆ นอกเหนือจากฟังก์ชั่นจะไม่สร้างขอบเขตใหม่ นั่นอธิบายว่าทำไม for-loops เขียนทับตัวแปรที่อยู่นอกขอบเขต:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
ใช้ฟังก์ชั่นแทน:
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10
ในตัวอย่างแรกไม่มีขอบเขตบล็อกดังนั้นตัวแปรที่ประกาศไว้ในตอนแรกจึงถูกเขียนทับ ในตัวอย่างที่สองมีขอบเขตใหม่เนื่องจากฟังก์ชันดังนั้นตัวแปรที่ประกาศในขั้นต้นคือ SHADOWED และไม่ถูกเขียนทับ
เกือบทั้งหมดที่คุณต้องรู้ในแง่ของการกำหนดขอบเขต JavaScript ยกเว้น:
ดังนั้นคุณจะเห็นว่าการกำหนดขอบเขต JavaScript นั้นง่ายมากจริงๆแม้ว่าจะไม่ได้หยั่งรู้เสมอไป สิ่งเล็ก ๆ น้อย ๆ ที่ควรระวัง:
ดังนั้นรหัสนี้:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
เทียบเท่ากับ:
var i = 1;
function abc() {
var i; // var declaration moved to the top of the scope
i = 2;
i = 3; // the assignment stays where it is
}
console.log(i);
สิ่งนี้อาจดูขัดกับสัญชาตญาณ แต่ก็สมเหตุสมผลจากมุมมองของนักออกแบบภาษาที่จำเป็น
const
' และ ' let
'คุณควรใช้การกำหนดขอบเขตบล็อกสำหรับตัวแปรทุกตัวที่คุณสร้างเช่นเดียวกับภาษาหลักอื่น ๆ ส่วนใหญ่ var
เป็นล้าสมัย ทำให้รหัสของคุณปลอดภัยและสามารถดูแลรักษาได้มากขึ้น
const
ควรจะใช้สำหรับ95% ของกรณี มันทำให้การอ้างอิงตัวแปรไม่สามารถเปลี่ยนแปลงได้ อาร์เรย์วัตถุและ DOM const
คุณสมบัติโหนดสามารถเปลี่ยนและมีแนวโน้มที่ควรจะเป็น
let
ควรใช้สำหรับตัวแปรใด ๆ ที่คาดว่าจะกำหนดใหม่ ซึ่งรวมถึงภายในวง let
ถ้าคุณเคยเปลี่ยนค่าเกินกว่าการเริ่มต้นใช้งาน
ขอบเขตบล็อกหมายถึงตัวแปรจะพร้อมใช้งานภายในวงเล็บเหลี่ยมที่ประกาศไว้เท่านั้น สิ่งนี้รวมถึงขอบเขตภายในรวมถึงฟังก์ชั่นที่ไม่ระบุชื่อที่สร้างขึ้นภายในขอบเขตของคุณ
ลองตัวอย่างที่อยากรู้อยากเห็นนี้ ในตัวอย่างด้านล่างหาก a มีตัวเลขเริ่มต้นที่ 0 คุณจะเห็น 0 แล้ว 1 ยกเว้น a คือวัตถุและ javascript จะส่ง f1 ตัวชี้ของแทนที่จะเป็นสำเนา ผลลัพธ์ก็คือคุณจะได้รับการแจ้งเตือนเดียวกันทั้งสองครั้ง
var a = new Date();
function f1(b)
{
b.setDate(b.getDate()+1);
alert(b.getDate());
}
f1(a);
alert(a.getDate());
มีขอบเขตฟังก์ชันใน JS เท่านั้น ไม่ปิดกั้นขอบเขต! คุณสามารถเห็นสิ่งที่ยกเกินไป
var global_variable = "global_variable";
var hoisting_variable = "global_hoist";
// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);
if (true) {
// The variable block will be global, on true condition.
var block = "block";
}
console.log("global_scope: - block: " + block);
function local_function() {
var local_variable = "local_variable";
console.log("local_scope: - local_variable: " + local_variable);
console.log("local_scope: - global_variable: " + global_variable);
console.log("local_scope: - block: " + block);
// The hoisting_variable is undefined at the moment.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
var hoisting_variable = "local_hoist";
// The hoisting_variable is now set as a local one.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}
local_function();
// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
ความเข้าใจของฉันคือว่ามี 3 ขอบเขต: ขอบเขตทั่วโลกพร้อมใช้งานทั่วโลก; ขอบเขตท้องถิ่นพร้อมใช้งานสำหรับฟังก์ชันทั้งหมดโดยไม่คำนึงถึงบล็อก และขอบเขตบล็อกมีให้เฉพาะกับบล็อกคำสั่งหรือนิพจน์ที่ใช้งานอยู่ ขอบเขตโกลบอลและโลคัลถูกระบุด้วยคีย์เวิร์ด 'var', ภายในฟังก์ชันหรือภายนอก, และขอบเขตบล็อกจะถูกระบุด้วยคีย์เวิร์ด 'let'
สำหรับผู้ที่เชื่อว่ามีขอบเขตระดับโลกและระดับท้องถิ่นเท่านั้นโปรดอธิบายว่าทำไม Mozilla จึงมีทั้งหน้าที่อธิบายความแตกต่างของขอบเขตการบล็อกใน JS
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
ปัญหาที่พบบ่อยมากยังไม่ได้อธิบายว่าตัวแปลงส่วนหน้ามักจะพบเจอคือขอบเขตที่สามารถมองเห็นได้โดยตัวจัดการเหตุการณ์แบบอินไลน์ใน HTML - ตัวอย่างเช่นด้วย
<button onclick="foo()"></button>
ขอบเขตของตัวแปรที่on*
แอตทริบิวต์สามารถอ้างอิงได้ต้องเป็น:
querySelector
เป็นตัวแปรแบบสแตนด์อโลนจะชี้ไปที่document.querySelector
หายาก)มิฉะนั้นคุณจะได้รับ ReferenceError เมื่อมีการเรียกใช้ตัวจัดการ ตัวอย่างเช่นหากตัวจัดการแบบอินไลน์อ้างอิงฟังก์ชันที่กำหนดไว้ภายใน window.onload
หรือ$(function() {
การอ้างอิงจะล้มเหลวเนื่องจากตัวจัดการแบบอินไลน์อาจอ้างอิงตัวแปรในขอบเขตส่วนกลางเท่านั้นและฟังก์ชันไม่ใช่แบบโกลบอล:
คุณสมบัติของdocument
และคุณสมบัติขององค์ประกอบที่ตัวจัดการติดอยู่อาจถูกอ้างถึงเป็นตัวแปรแบบสแตนด์อโลนภายในตัวจัดการแบบอินไลน์เพราะตัวจัดการแบบอินไลน์ถูกเรียกใช้ภายในสองwith
บล็อกหนึ่งสำหรับdocument
หนึ่งสำหรับองค์ประกอบ ขอบเขตขอบเขตของตัวแปรภายในตัวจัดการเหล่านี้ไม่ได้ใช้งานง่ายมากและผู้จัดการเหตุการณ์ทำงานอาจต้องใช้ฟังก์ชันเป็นโกลบอล (และควรหลีกเลี่ยงมลภาวะระดับโลกที่ไม่จำเป็น)
เนื่องจากขอบเขตของโซ่ภายในตัวจัดการแบบอินไลน์นั้นแปลกมากและเนื่องจากตัวจัดการแบบอินไลน์ต้องการมลพิษทั่วโลกในการทำงานและเนื่องจากบางครั้งตัวจัดการแบบอินไลน์ต้องใช้สตริงที่น่าเกลียดเมื่อหนีผ่านการโต้แย้งจึงอาจหลีกเลี่ยงได้ ให้แนบตัวจัดการเหตุการณ์โดยใช้ Javascript (เช่นเดียวกับaddEventListener
) แทนที่จะใช้มาร์กอัป HTML
ในบันทึกย่อที่แตกต่างจาก<script>
แท็กปกติซึ่งทำงานที่ระดับบนสุดโค้ดภายในโมดูล ES6 ทำงานในขอบเขตส่วนตัวของตนเอง ตัวแปรที่กำหนดที่ด้านบนของ<script>
แท็กปกติคือโกลบอลดังนั้นคุณสามารถอ้างอิงได้ใน<script>
แท็กอื่นเช่นนี้
แต่ระดับสูงสุดของโมดูล ES6 นั้นไม่ใช่ระดับโลก ตัวแปรที่ประกาศที่ด้านบนของโมดูล ES6 จะสามารถมองเห็นได้ภายในโมดูลนั้นเท่านั้นยกเว้นว่าตัวแปรนั้นได้รับการแก้ไขอย่างชัดเจนexport
หรือเว้นแต่ได้รับการกำหนดให้กับคุณสมบัติของออบเจ็กต์ทั่วโลก
ระดับบนสุดของโมดูล ES6 จะคล้ายกับที่ภายในของ IIFE <script>
ในระดับบนในปกติ โมดูลสามารถอ้างอิงตัวแปรใด ๆ ที่เป็นโกลบอลและไม่มีสิ่งใดที่สามารถอ้างอิงอะไรได้ภายในโมดูลยกเว้นว่าโมดูลนั้นได้รับการออกแบบอย่างชัดเจน
ใน JavaScript มีขอบเขตสองประเภท:
carName
ฟังก์ชั่นด้านล่างมีตัวแปรขอบเขตท้องถิ่น และตัวแปรนี้ไม่สามารถเข้าถึงได้จากนอกฟังก์ชั่น
function myFunction() {
var carName = "Volvo";
alert(carName);
// code here can use carName
}
carName
ด้านล่างชั้นมีตัวแปรขอบเขตทั่วโลก และตัวแปรนี้สามารถเข้าถึงได้จากทุกที่ในชั้นเรียน
class {
var carName = " Volvo";
// code here can use carName
function myFunction() {
alert(carName);
// code here can use carName
}
}
ES5
และก่อนหน้านี้:ตัวแปรใน Javascript นั้นเริ่มแรก (ก่อนES6
) กำหนดขอบเขตของฟังก์ชัน คำที่กำหนดขอบเขตศัพท์หมายถึงคุณสามารถดูขอบเขตของตัวแปรโดย 'ดู' ที่โค้ด
ทุกตัวแปรที่ประกาศพร้อมกับvar
คีย์เวิร์ดจะถูกกำหนดขอบเขตให้กับฟังก์ชัน อย่างไรก็ตามหากมีการประกาศฟังก์ชันอื่นภายในฟังก์ชันนั้นฟังก์ชันเหล่านั้นจะสามารถเข้าถึงตัวแปรของฟังก์ชันภายนอกได้ นี้เรียกว่าห่วงโซ่ขอบเขต มันทำงานในลักษณะดังต่อไปนี้:
// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';
function outerFunc () {
// outerFunc scope
var foo = 'outerFunc';
var foobar = 'outerFunc';
innerFunc();
function innerFunc(){
// innerFunc scope
var foo = 'innerFunc';
console.log(foo);
console.log(bar);
console.log(foobar);
}
}
outerFunc();
จะเกิดอะไรขึ้นเมื่อเรากำลังพยายามที่จะเข้าสู่ระบบตัวแปรfoo
, bar
และfoobar
ไปยังคอนโซลคือต่อไปนี้:
innerFunc
ตัวเอง ดังนั้นมูลค่าของ foo innerFunc
ได้รับการแก้ไขเพื่อสตริงinnerFunc
เอง ดังนั้นเราจึงจำเป็นที่จะต้องปีนโซ่ขอบเขต ก่อนอื่นเราดูในฟังก์ชั่นด้านนอกซึ่งฟังก์ชั่นที่innerFunc
ถูกกำหนด outerFunc
นี้เป็นฟังก์ชั่น ในขอบเขตของouterFunc
เราสามารถหาแถบตัวแปรซึ่งเก็บสตริง 'outerFunc'ES6
(ES 2015) และมากกว่า:แนวคิดเดียวกันของขอบเขต lexically และ scopechain ES6
ยังคงใช้ใน อย่างไรก็ตามมีวิธีการใหม่ในการประกาศตัวแปร มีดังต่อไปนี้:
let
: สร้างตัวแปรที่กำหนดขอบเขตของบล็อกconst
: สร้างตัวแปรที่กำหนดขอบเขตบล็อกซึ่งจะต้องเริ่มต้นและไม่สามารถกำหนดใหม่ได้ความแตกต่างที่ใหญ่ที่สุดระหว่างvar
และlet
/ const
คือว่าvar
เป็นหน้าที่กำหนดขอบเขตในขณะที่let
/ const
มีบล็อกขอบเขต นี่คือตัวอย่างที่แสดงให้เห็นถึงสิ่งนี้:
let letVar = 'global';
var varVar = 'global';
function foo () {
if (true) {
// this variable declared with let is scoped to the if block, block scoped
let letVar = 5;
// this variable declared with let is scoped to the function block, function scoped
var varVar = 10;
}
console.log(letVar);
console.log(varVar);
}
foo();
ในตัวอย่างด้านบน letVar บันทึกค่าโกลบอลเนื่องจากตัวแปรที่ประกาศด้วยlet
ถูกบล็อกขอบเขต พวกเขาหยุดอยู่นอกบล็อกที่เกี่ยวข้องดังนั้นจึงไม่สามารถเข้าถึงตัวแปรภายนอกบล็อก if
ใน EcmaScript5 มีสองส่วนใหญ่ขอบเขตขอบเขตท้องถิ่นและขอบเขตทั่วโลกแต่ใน EcmaScript6 เรามีหลักสามขอบเขตขอบเขตท้องถิ่นขอบเขตทั่วโลกและขอบเขตที่เรียกว่าใหม่ขอบเขตบล็อก
ตัวอย่างขอบเขตของบล็อกคือ: -
for ( let i = 0; i < 10; i++)
{
statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
ECMAScript 6 แนะนำคำหลัก let และ const คำหลักเหล่านี้สามารถใช้แทนคำหลัก var ตรงกันข้ามกับคำหลัก var คีย์เวิร์ด let และ const สนับสนุนการประกาศขอบเขตโลคัลภายในข้อความสั่ง block
var x = 10
let y = 10
const z = 10
{
x = 20
let y = 20
const z = 20
{
x = 30
// x is in the global scope because of the 'var' keyword
let y = 30
// y is in the local scope because of the 'let' keyword
const z = 30
// z is in the local scope because of the 'const' keyword
console.log(x) // 30
console.log(y) // 30
console.log(z) // 30
}
console.log(x) // 30
console.log(y) // 20
console.log(z) // 20
}
console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
ฉันชอบคำตอบที่ได้รับการยอมรับ แต่ต้องการเพิ่มสิ่งนี้:
ขอบเขตรวบรวมและเก็บรักษารายการค้นหาของตัวระบุที่ประกาศไว้ทั้งหมด (ตัวแปร) และบังคับใช้ชุดของกฎที่เข้มงวดเกี่ยวกับวิธีที่สิ่งเหล่านี้สามารถเข้าถึงได้ในการเรียกใช้โค้ดในปัจจุบัน
ขอบเขตคือชุดของกฎสำหรับค้นหาตัวแปรโดยใช้ชื่อตัวระบุ
JavaScript มีขอบเขตสองประเภท
ขอบเขตทั่วโลก : ตัวแปรที่ประกาศในขอบเขตทั่วโลกสามารถใช้ได้ทุกที่ในโปรแกรมอย่างราบรื่น ตัวอย่างเช่น:
var carName = " BMW";
// code here can use carName
function myFunction() {
// code here can use carName
}
ขอบเขตการทำงานหรือขอบเขตภายใน : ตัวแปรที่ประกาศในขอบเขตนี้สามารถใช้ในฟังก์ชั่นของตนเองเท่านั้น ตัวอย่างเช่น:
// code here can not use carName
function myFunction() {
var carName = "BMW";
// code here can use carName
}