ต้องบอกก่อนว่าผมไม่ใช้ Guru ด้าน Javascript นะครับ เป็นเพียงแค่มือใหม่ที่เพิ่งหัดศึกษาเท่านั้น ส่วนมากก็จะตามเทรนด์ไปเรื่อยๆ เน้นอ่าน Documentation แล้วเอามาประยุกต์ใช้กับงาน เช่น Node.js, Meteor.js, Sails.js, Express.js, Angular.js, Ember.js, jQuery, Backbone, etc. อีกเยอะแยะเลย มีอะไรใหม่ๆ ผมก็ชอบไปลองเล่นไปเรื่อยๆ จนตอนหลังรู้สึกว่าหากเราไม่มีพวก Library พวกนี้ เราจะเขียน Javascript เองได้หรือเปล่านะ ? (รู้สึกเหมือนตัวเองเป็นแค่ User ที่อ่านเอกสารคู่มือเท่านั้น) ตอนหลังก็เลยเริ่มอ่านบทความที่เป็น Javascript จริงๆจังๆ แต่ก็อ่านเฉพาะ Javascript จนถึงวันนี้ ได้อ่านเรื่อง Variable Hoisting แล้วรู้สึกมันทำให้ผมสับสนดียิ่งนัก ก็เลยถือโอกาสนี้เขียนเป็นบล็อกสรุปสิ่งที่เข้าใจไว้ เผื่อไว้อ่านในอนาคต
Hoisting คืออะไร ?
ก่อนที่จะขยายนิยามคำว่า Hoist หรือ Hoisting ใน Javascript ว่ามันคืออะไร ลองดูโค๊ดด้านล่างนี้ก่อน
for (var i = 1; i < 10; i++) {
// ...
}
console.log(i);
จากโค๊ดด้านบนหากให้ลองตอบคำถาม ว่า console.log(i)
จะได้คำตอบเป็นอะไร เชื่อว่าหลายๆคนต้องตอบว่า undefined
หรือบางคนอาจจะตอบว่า error แน่นอนซึ่งคำตอบทั้งหมดนั้น ผิดครับ (ผมเห็นทีแรกก่อนลองเทส ผมก็ตอบว่า undefined
:))
จริงๆแล้วคำตอบของมันคือ 10 ไม่เชื่อเทสกับ Browser ดู แล้วทำไมเป็นยังงั้นละ?
มันคือส่วนหนึ่งของ Hoisting ไงละครับ Hoisting ก็คือ การเลื่อนหรือย้ายตัวแปรไปไว้ที่ส่วนบนสุดของสโคป/ฟังค์ชัน
อ่านมาถึงตรงนี้บางคนอาจจะงงหรือยังไม่เห็นภาพ ผมก็ยังงง อ่านต่อครับ :)
Global Scope กับ Local Scope
Global Scope คือตัวแปรที่สามารถเข้าถึงได้ทุกที่ตราบใดที๋โปรแกรมยังคงทำงานอยู่ ประกาศตัวแปร ทำได้โดยไม่ต้องมี var
เช่น
name = 'Chai';
ส่วน Local Scope คือตัวแปรที่ทำงานอยู่ภายใน scope ของมันเช่น ภายใน Loop ภายใน Function (, [ หรือ [
เช่น
var name = 'Chai';
โดยถ้าหากว่าเราทำการอ้างถึงตัวแปร Local นอก Scope ก็จะทำให้เกิด Error เช่นโค๊ดด้านล่างนี้
function sayHello() {
var name = 'Chai';
}
console.log(name); // ReferenceError: name is not defined
แต่ว่าการกำหนดตัวแปรด้วยการใส่คีย์เวิร์ด var
ก็เป็นตัวแปร Global ได้เช่นกันนะครับ ถ้ากำหนดไว้ที่นอกสุดของ scope เช่น
var name = 'Chai';
function sayHello() {
console.log(name);
}
sayHello(); // Chai
ภายในฟังค์ชั่น sayHello()
ทั้งที่ไม่ได้ประกาศตัวแปร Local ใดๆไว้เลย แต่สามารถเข้าถึงตัวแปร name
ได้ ก็เพราะว่าตัวแปร name
เป็น Global Variable นั่นเอง
เอ๊แล้วแบบนี้ โค๊ดด้านล่างนี้ ตัวแปร name
ใช่ Global Variable หรือเปล่า?
function sayHello() {
for (var i = 1; i < 5; i++) {
var name = 'Chai';
}
console.log(name);
}
sayHello(); // Name
ตอบเลยว่า ไม่ใช่ครับ ตัวแปร name
ด้านบนเป็น Local Variable
แต่ทำไม สามารถที่จะเข้าถึง name
ได้ทั้งๆที่มันเป็นตัวแปร Local อยู่ภายใน For Loop เท่านั้น ? คำตอบคือ เพราะ hoists ครับ
ทำให้ตัวแปร name
ไปอยู่บนสุดของ Scope อยู่ภายในฟังค์ชั่น sayHello
ก่อน For Loop ทีนี้เวลา console.log(name)
ก็เลยทำให้สามารถพิมพ์ค่าออกมาได้นั่นเอง
Variable Declaration vs Variable Assigment
ใน Javascript การประกาศตัวแปร จะทำทั้งหมด 2 ขั้นตอนครับคือ ขั้นแรก
- Declaration : คือการประกาศชื่อตัวแปร เช่น
var name;
- Assignment : คือขั้นตอนการกำหนดค่า เช่น
name = 'Chai';
var name = 'Chai';
โค๊ดด้านบนคือ Declare ก่อนและทำการ Assign ค่า
ทีนี้ไอ้เจ้า Declaration และ Assignment มันเกี่ยวอะไรกับ Hoists ละ ก็เพราะว่าจุดสำคัญของ Hoists เลยคือมันเคลื่อนย้ายตัวแปร ไปยังจุดบนสุดของ Scope แต่มีข้อแม้ว่า ย้ายเฉพาะตัวแปรในขั้น Variable Declaration เท่านั้น
จากโค๊ดเดิม
function sayHello() {
for (var i = 1; i < 5; i++) {
var name = 'Chai';
}
console.log(name);
}
sayHello(); // Name
เมื่อมัน Hoists ตัวแปร name
(Declaration) ก็จะย้ายไปอยู่บนสุดของสโคป ส่วนขั้นตอน Assignment จะไม่ถูกย้ายไปด้วย เพราะมันไม่ใช่ Hoists จะกลายเป็น
function sayHello() {
var name; // Declaration
for (var i = 1; i < 5; i++) {
name = 'Chai';
}
console.log(name);
}
sayHello(); // Name
สรุป
สรุปประเด็นจากคำถามที่ผมจั่วหัวไว้ครับ ว่าทำไมถึงได้ 10 คงหายสงสัยกันแล้วนะครับ
for (var i = 1; i < 10; i++) {
// ...
}
console.log(i);
ถึงได้คำตอบ 10 ก็เพราะว่า ตรง for loop for (var i = 1; i <= 10; i++)
ได้ประกาศตัวแปร i (declaration) ฉะนั้นตัวแปร i ก็จะถูก hoisting คือการย้ายไปส่วนบนสุด ก็เลยกลายเป็น
var i;
for (i = 1; i < 10; i++) {
// ...
}
console.log(i);
หลังจากนั้นก็วนลูป console.log(i)
ก็เลยมีค่าเท่ากับ 10 ด้วยประกาศฉะนี้
ฉะนั้นจึงสรุปได้ว่า เมื่อใดก็ตามที่เราเริ่มทำการประกาศตัวแปร (Declaration Variable) ก็จะเกิดการเคลื่อนย้ายตัวแปร ไปยังด้านบนสุดของสโคปทันที เราเรียกสิ่งนี้ว่า Hoists
สุดท้ายทั้งหมดผมก็สรุปจากความเข้าใจของตัวเองนะครับ ไม่รับประกันว่าผมเข้าใจถูกทั้งหมดหรือไม่ หากท่านผู้อ่าน ที่ผ่านเข้ามาอ่านบทความนี้ แล้วเกิดพบว่าข้อมูลของผิดพลาด จะขอบคุณมากถ้าท่านช่วยแนะนำส่วนที่ถูกต้อง หรือช่วยสอนในสิ่งที่ผมเข้าใจผิดไป ส่วนแหล่งที่มาก็มาจากหลายๆแหล่ง ผมเขียนไว้ท้ายสุดแล้ว สามารถอ่านเพิ่มเติมได้ครับ น่าจะเข้าใจกว่าของผมอีกนะ ขอบคุณครับ
References :
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit