ตัวแปรคือโครงสร้างข้อมูลที่กําหนดชื่อตัวแทนให้กับค่า โดยจะมีข้อมูลประเภทใดก็ได้
ชื่อของตัวแปรเรียกว่าตัวระบุ ตัวระบุที่ถูกต้องต้องเป็นไปตามกฎต่อไปนี้
- ตัวระบุอาจมีตัวอักษร Unicode, เครื่องหมายดอลลาร์ ($), อักขระขีดล่าง (_), ตัวเลข (0-9) และแม้แต่อักขระ Unicode บางตัว
- ตัวระบุต้องไม่มีช่องว่าง เนื่องจากโปรแกรมแยกวิเคราะห์ใช้ช่องว่างเพื่อแยกองค์ประกอบอินพุต ตัวอย่างเช่น หากคุณพยายามเรียกตัวแปร
my Variable
แทนmyVariable
โปรแกรมแยกวิเคราะห์จะเห็นตัวระบุ 2 รายการ ได้แก่my
และVariable
และแสดงข้อผิดพลาดทางไวยากรณ์ ("โทเค็นที่ไม่คาดคิด: ตัวระบุ") ตัวระบุต้องขึ้นต้นด้วยตัวอักษร เครื่องหมายขีดล่าง (
_
) หรือเครื่องหมายดอลลาร์ ($
) ต้องไม่ขึ้นต้นด้วยตัวเลขเพื่อป้องกันความสับสนระหว่างตัวเลขกับตัวระบุlet 1a = true; > Uncaught SyntaxError: Invalid or unexpected token
หาก JavaScript อนุญาตตัวเลขที่จุดเริ่มต้นของตัวระบุ ก็จะอนุญาตให้ใช้ตัวระบุที่ประกอบด้วยตัวเลขเท่านั้น ซึ่งจะทำให้เกิดความขัดแย้งระหว่างตัวเลขที่ใช้เป็นตัวเลขและตัวเลขที่ใช้เป็นตัวระบุ
let 10 = 20 10 + 5 > ?
"คําที่สงวนไว้" ที่มีความหมายทางไวยากรณ์อยู่แล้วจะใช้เป็นตัวระบุไม่ได้
ตัวระบุต้องไม่มีสัญลักษณ์พิเศษ (
! . , / \ + - * =
)
ต่อไปนี้ไม่ใช่กฎที่เข้มงวดสำหรับการสร้างตัวระบุ แต่เป็นแนวทางปฏิบัติแนะนำของอุตสาหกรรมที่จะช่วยให้การดูแลรักษาโค้ดง่ายขึ้น หากโปรเจ็กต์หนึ่งๆ มีมาตรฐานที่แตกต่างออกไป ให้ทำตามมาตรฐานเหล่านั้นเพื่อให้สอดคล้องกัน
ตามตัวอย่างที่เมธอดและพร็อพเพอร์ตี้ในตัวของ JavaScript กำหนดไว้ รูปแบบ Camel Case (หรือ "camelCase") เป็นรูปแบบที่ใช้กันโดยทั่วไปมากสำหรับตัวระบุที่ประกอบด้วยหลายคำ รูปแบบ Camel Case คือการใช้ตัวพิมพ์ใหญ่เป็นตัวอักษรแรกในทุกคำยกเว้นคำแรกเพื่อให้อ่านง่ายขึ้นโดยไม่ต้องเว้นวรรค
let camelCasedIdentifier = true;
โปรเจ็กต์บางโปรเจ็กต์ใช้รูปแบบการตั้งชื่ออื่นๆ โดยขึ้นอยู่กับบริบทและลักษณะของข้อมูล เช่น โดยทั่วไปแล้วตัวอักษรแรกของคลาสจะเป็นตัวพิมพ์ใหญ่ ชื่อคลาสที่มีหลายคำจึงมักใช้รูปแบบ Camel Case ที่เรียกกันทั่วไปว่า "Upper Camel Case" หรือรูปแบบPascal
class MyClass {
}
ตัวระบุควรอธิบายลักษณะของข้อมูลที่เก็บไว้อย่างกระชับ (เช่น currentMonthDays
เป็นชื่อที่ดีกว่า theNumberOfDaysInTheCurrentMonth
) และอ่านได้ชัดเจนโดยย่อ (originalValue
ดีกว่า val
) ตัวระบุ myVariable
ที่ใช้ตลอดทั้งโมดูลนี้ใช้ได้ในบริบทของตัวอย่างแบบแยกต่างหาก แต่จะไม่ค่อยมีประโยชน์ในโค้ดเวอร์ชันที่ใช้งานจริงเนื่องจากไม่ได้ให้ข้อมูลเกี่ยวกับข้อมูลที่เก็บไว้
ตัวระบุไม่ควรระบุข้อมูลอย่างเจาะจงมากเกินไป เนื่องจากค่าอาจเปลี่ยนแปลงได้ขึ้นอยู่กับวิธีที่สคริปต์ดำเนินการกับข้อมูลนั้น หรือขึ้นอยู่กับการตัดสินใจของผู้ดูแลระบบในอนาคต เช่น ตัวแปรที่ได้รับตัวระบุ miles
เดิมอาจต้องเปลี่ยนเป็นค่าเป็นกิโลเมตรในภายหลังในโปรเจ็กต์ ซึ่งทำให้ผู้ดูแลต้องเปลี่ยนการอ้างอิงตัวแปรนั้นเพื่อไม่ให้เกิดความสับสนในอนาคต โปรดใช้ distance
เป็นตัวระบุแทนเพื่อหลีกเลี่ยงปัญหานี้
JavaScript ไม่ได้ให้สิทธิ์หรือความหมายพิเศษใดๆ แก่ตัวระบุที่ขึ้นต้นด้วยเครื่องหมายขีดล่าง (_
) แต่โดยทั่วไปแล้วจะใช้เพื่อระบุว่าตัวแปร เมธอด หรือพร็อพเพอร์ตี้นั้น "เป็นแบบส่วนตัว" ซึ่งหมายความว่ามีไว้เพื่อใช้ในบริบทของออบเจ็กต์ที่มีตัวแปร เมธอด หรือพร็อพเพอร์ตี้นั้นเท่านั้น และไม่ควรเข้าถึงหรือแก้ไขนอกบริบทนั้น รูปแบบนี้เป็นรูปแบบที่รับมาจากภาษาโปรแกรมอื่นๆ และอยู่ก่อนการเพิ่มพร็อพเพอร์ตี้ส่วนตัวของ JavaScript
การประกาศตัวแปร
มีหลายวิธีในการทําให้ JavaScript ทราบตัวระบุ ซึ่งเป็นกระบวนการที่เรียกว่า "การประกาศ" ตัวแปร ประกาศตัวแปรโดยใช้คีย์เวิร์ด let
, const
หรือ var
let myVariable;
ใช้ let
หรือ var
เพื่อประกาศตัวแปรที่เปลี่ยนแปลงได้ทุกเมื่อ คีย์เวิร์ดเหล่านี้บอกโปรแกรมแปลภาษา JavaScript ว่าสตริงอักขระเป็นตัวระบุที่อาจมีค่า
เมื่อทํางานในโค้ดเบสสมัยใหม่ ให้ใช้ let
แทน var
var
ยังใช้งานได้ในเบราว์เซอร์สมัยใหม่ แต่มีพฤติกรรมบางอย่างที่ใช้งานยากซึ่งกำหนดไว้ใน JavaScript เวอร์ชันแรกๆ และไม่สามารถเปลี่ยนแปลงได้ในภายหลังเพื่อรักษาความเข้ากันได้ย้อนหลัง let
เพิ่มเข้ามาใน ES6 เพื่อแก้ไขปัญหาบางอย่างเกี่ยวกับการออกแบบ var
ตัวแปรที่ประกาศจะเริ่มต้นด้วยการกําหนดค่าให้กับตัวแปร ใช้เครื่องหมายเท่ากับ (=
) ตัวเดียวเพื่อกําหนดหรือกําหนดค่าใหม่ให้กับตัวแปร คุณดำเนินการนี้เป็นส่วนหนึ่งของคำสั่งเดียวกันที่ประกาศได้
let myVariable = 5;
myVariable + myVariable
> 10
นอกจากนี้ คุณยังประกาศตัวแปรด้วย let
(หรือ var
) โดยไม่ต้องเริ่มต้นตัวแปรในทันทีได้ด้วย หากกำหนดค่าเริ่มต้น ค่าเริ่มต้นของตัวแปรจะเป็น undefined
จนกว่าโค้ดจะกําหนดค่าให้
let myVariable;
myVariable;
> undefined
myVariable = 5;
myVariable + myVariable
> 10
ตัวแปรที่มีค่า undefined
แตกต่างจากตัวแปรที่ไม่มีคําจํากัดความซึ่งยังไม่ได้ประกาศตัวระบุ การอ้างอิงตัวแปรที่คุณไม่ได้ประกาศจะทำให้เกิดข้อผิดพลาด
myVariable
> Uncaught ReferenceError: myVariable is not defined
let myVariable;
myVariable
> undefined
โดยทั่วไปการเชื่อมโยงตัวระบุกับค่าเรียกว่า "การเชื่อมโยง"
ไวยากรณ์ที่อยู่หลังคีย์เวิร์ด let
, var
หรือ const
เรียกว่า "รายการการเชื่อมโยง" และอนุญาตให้มีการประกาศตัวแปรหลายรายการที่คั่นด้วยคอมมา (ลงท้ายด้วยเซมิโคลอนตามที่คาดไว้) ซึ่งทําให้ข้อมูลโค้ดต่อไปนี้ทํางานเหมือนกัน
let firstVariable,
secondVariable,
thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;
การกำหนดค่าตัวแปรใหม่จะไม่ใช้ let
(หรือ var
) เนื่องจาก JavaScript ทราบอยู่แล้วว่ามีตัวแปรอยู่
let myVariable = true;
myVariable
> true
myVariable = false;
myVariable
> false
คุณสามารถกําหนดค่าใหม่ให้กับตัวแปรโดยอิงตามค่าที่มีอยู่ได้ ดังนี้
let myVariable = 10;
myVariable
> 10
myVariable = myVariable * myVariable;
myVariable
> 100
หากคุณพยายามประกาศตัวแปรอีกครั้งโดยใช้ let
ในสภาพแวดล้อมที่ใช้งานจริง คุณจะได้รับข้อผิดพลาดเกี่ยวกับไวยากรณ์
let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable
เครื่องมือสําหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์จะอนุญาตการประกาศ let
(และ class
) อีกครั้งได้มากกว่า คุณจึงอาจไม่เห็นข้อผิดพลาดเดียวกันในคอนโซลนักพัฒนาซอฟต์แวร์
var
อนุญาตให้ประกาศซ้ำโดยไม่จำเป็นเพื่อรักษาความเข้ากันได้กับเบราว์เซอร์รุ่นเดิม โดยจะไม่มีข้อผิดพลาดในบริบทใดๆ ดังนี้
var myVariable = true;
var myVariable = false;
myVariable\
> false
const
ใช้คีย์เวิร์ด const
เพื่อประกาศค่าคงที่ ซึ่งเป็นตัวแปรประเภทหนึ่งที่ต้องมีการเริ่มต้นค่าทันทีและจะเปลี่ยนแปลงไม่ได้ ตัวระบุสำหรับค่าคงที่จะใช้กฎเดียวกันกับตัวแปรที่ประกาศโดยใช้ let
(และ var
) ดังนี้
const myConstant = true;
myConstant
> true
คุณไม่สามารถประกาศค่าคงที่โดยไม่กําหนดค่าให้ทันที เนื่องจากค่าคงที่ไม่สามารถกําหนดค่าใหม่ได้หลังจากสร้างแล้ว ค่าคงที่ที่ไม่ได้เริ่มต้นจะยังคงเป็น undefined
ตลอดไป หากพยายามประกาศค่าคงที่โดยไม่เริ่มต้นค่า คุณจะได้รับข้อผิดพลาดเกี่ยวกับไวยากรณ์
const myConstant;
Uncaught SyntaxError: missing = in const declaration
การพยายามเปลี่ยนค่าของตัวแปรที่ประกาศด้วย const
ในลักษณะที่คุณอาจเปลี่ยนค่าของตัวแปรที่ประกาศด้วย let
(หรือ var
) จะทำให้เกิดข้อผิดพลาดประเภทนี้
const myConstant = true;
myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'
อย่างไรก็ตาม เมื่อคонстантเชื่อมโยงกับออบเจ็กต์ พร็อพเพอร์ตี้ของออบเจ็กต์นั้นจะเปลี่ยนแปลงได้
const constantObject = { "firstvalue" : true };
constantObject
> Object { firstvalue: true }
constantObject.secondvalue = false;
constantObject
> Object { firstvalue: true, secondvalue: false }
ค่าคงที่ที่มีออบเจ็กต์เป็นการอ้างอิงค่าข้อมูลที่เปลี่ยนแปลงได้ซึ่งแก้ไขไม่ได้ แม้ว่าคุณจะเปลี่ยนแปลงค่าคงที่ไม่ได้ แต่คุณก็สามารถแก้ไข เพิ่ม หรือนําคุณสมบัติของออบเจ็กต์ที่อ้างอิงออกได้ ดังนี้
const constantObject = { "firstvalue" : true };
constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'
เมื่อคุณไม่ต้องการให้มีการกําหนดตัวแปรใหม่ แนวทางปฏิบัติแนะนำคือให้ตัวแปรเป็นค่าคงที่ การใช้ const
บอกให้ทีมพัฒนาซอฟต์แวร์หรือผู้ดูแลโปรเจ็กต์ในอนาคตอย่าเปลี่ยนแปลงค่านั้น เพื่อหลีกเลี่ยงการละเมิดสมมติฐานที่โค้ดของคุณทำเกี่ยวกับวิธีการใช้งาน เช่น ตัวแปรจะได้รับการประเมินตามประเภทข้อมูลที่คาดไว้ในที่สุด
ขอบเขตตัวแปร
ขอบเขตของตัวแปรคือส่วนของสคริปต์ที่มีตัวแปรนั้น
นอกขอบเขตของตัวแปร ระบบจะไม่กำหนดตัวแปรนั้น ตัวแปรจะไม่ได้เป็นตัวระบุที่มีค่า undefined
แต่จะเหมือนกับว่าไม่มีการประกาศตัวแปรนั้น
คุณสามารถกําหนดขอบเขตตัวแปรไปยังบล็อกคำสั่ง (ขอบเขตบล็อก) ฟังก์ชันแต่ละรายการ (ขอบเขตฟังก์ชัน) หรือทั้งแอปพลิเคชัน JavaScript (ขอบเขตส่วนกลาง) ทั้งนี้ขึ้นอยู่กับคีย์เวิร์ดที่คุณใช้ประกาศตัวแปรและบริบทที่คุณกําหนด
ขอบเขตการบล็อก
ตัวแปรที่คุณประกาศโดยใช้ let
หรือ const
จะมีขอบเขตเป็นคำสั่งบล็อกที่อยู่ใกล้ที่สุด ซึ่งหมายความว่าจะเข้าถึงตัวแปรได้ภายในบล็อกนั้นเท่านั้น การพยายามเข้าถึงตัวแปรระดับบล็อกนอกบล็อกที่บรรจุจะทำให้เกิดข้อผิดพลาดเดียวกันกับการพยายามเข้าถึงตัวแปรที่ไม่มีอยู่
{
let scopedVariable = true;
console.log( scopedVariable );
}
> true
scopedVariable
> ReferenceError: scopedVariable is not defined
ในแง่ของ JavaScript ตัวแปรระดับบล็อกไม่มีอยู่นอกบล็อกที่มีตัวแปรนั้น เช่น คุณสามารถประกาศค่าคงที่ภายในบล็อก แล้วประกาศค่าคงที่อีกรายการหนึ่งนอกบล็อกที่ใช้ตัวระบุเดียวกัน ดังนี้
{
const myConstant = false;
}
const myConstant = true;
scopedConstant;
> true
แม้ว่าตัวแปรที่ประกาศจะขยายไปยังบล็อกหลักไม่ได้ แต่จะใช้ได้กับบล็อกที่สืบทอดทั้งหมด ดังนี้
{
let scopedVariable = true;
{
console.log( scopedVariable );
}
}
> true
ค่าของตัวแปรที่ประกาศไว้สามารถเปลี่ยนแปลงได้จากภายในบล็อกที่สืบทอด
{
let scopedVariable = false;
{
scopedVariable = true;
}
console.log( scopedVariable );
}
> true
ตัวแปรใหม่สามารถเริ่มต้นด้วย let
หรือ const
ภายในบล็อกที่สืบทอดได้โดยไม่มีข้อผิดพลาด แม้ว่าจะใช้ตัวระบุเดียวกันกับตัวแปรในบล็อกหลักก็ตาม
{
let scopedVariable = false;
{
let scopedVariable = true;
}
console.log( scopedVariable );
}
> false
ขอบเขตของฟังก์ชัน
ตัวแปรที่ประกาศโดยใช้ var
จะมีขอบเขตอยู่ในฟังก์ชันที่ใกล้ที่สุดซึ่งบรรจุตัวแปรนั้นไว้ (หรือบล็อกการเริ่มต้นแบบคงที่ภายในคลาส)
function myFunction() {
var scopedVariable = true;
return scopedVariable;
}
scopedVariable;
> ReferenceError: scopedVariable is not defined
ซึ่งยังคงเป็นเช่นนั้นหลังจากที่เรียกใช้ฟังก์ชันแล้ว แม้ว่าจะมีการเริ่มต้นตัวแปรขณะที่ฟังก์ชันทำงาน แต่ตัวแปรดังกล่าวจะยังคงใช้ไม่ได้นอกขอบเขตของฟังก์ชัน
function myFunction() {
var scopedVariable = true;
return scopedVariable;
}
scopedVariable;
> ReferenceError: scopedVariable is not defined
myFunction();
> true
scopedVariable;
> ReferenceError: scopedVariable is not defined
ขอบเขตส่วนกลาง
ตัวแปรส่วนกลางจะใช้ได้ทั่วทั้งแอปพลิเคชัน JavaScript ทั้งหมด ไม่ว่าจะอยู่ภายในบล็อกและฟังก์ชันใดก็ตาม ไปจนถึงสคริปต์ใดก็ได้ในหน้า
แม้ว่าการตั้งค่าเริ่มต้นนี้อาจดูเป็นการตั้งค่าที่ต้องการ แต่ตัวแปรที่ส่วนใดก็ได้ของแอปพลิเคชันเข้าถึงและแก้ไขได้อาจเพิ่มค่าใช้จ่ายที่ไม่จำเป็น หรืออาจทำให้เกิดข้อขัดแย้งกับตัวแปรในส่วนอื่นๆ ของแอปพลิเคชันที่มีตัวระบุเดียวกัน ซึ่งมีผลกับ JavaScript ทั้งหมดที่เกี่ยวข้องกับการแสดงผลของหน้าเว็บ รวมถึงสิ่งต่างๆ เช่น ไลบรารีของบุคคลที่สามและข้อมูลวิเคราะห์ผู้ใช้ ดังนั้น แนวทางปฏิบัติแนะนำคือหลีกเลี่ยงการทำให้ขอบเขตระดับบนสุดสกปรกทุกครั้งที่ทำได้
ตัวแปรที่ประกาศโดยใช้ var
นอกฟังก์ชันหลัก หรือใช้ let
หรือ const
นอกบล็อกหลักจะเป็นตัวแปรส่วนกลาง
var functionGlobal = true; // Global
let blockGlobal = true; // Global
{
console.log( blockGlobal );
console.log( functionGlobal );
}
> true
> true
(function() {
console.log( blockGlobal );
console.log( functionGlobal );
}());
> true
> true
การกำหนดค่าให้กับตัวแปรโดยไม่ประกาศอย่างชัดแจ้ง (กล่าวคือ ไม่ได้ใช้ var
, let
หรือ const
เพื่อสร้าง) จะยกระดับตัวแปรขึ้นสู่ขอบเขตส่วนกลาง แม้ว่าจะเริ่มต้นภายในฟังก์ชันหรือบล็อกก็ตาม บางครั้งตัวแปรที่สร้างโดยใช้รูปแบบนี้จะเรียกว่า "ตัวแปรส่วนกลางโดยนัย"
function myFunction() {
globalVariable = "global";
return globalVariable
}
myFunction()\
> "global"
globalVariable\
> "global"
การยกแบบปรับได้
ระบบจะยกระดับการประกาศตัวแปรและฟังก์ชันไปไว้ที่ด้านบนสุดของสโคป ซึ่งหมายความว่าโปรแกรมแปลภาษา JavaScript จะประมวลผลตัวแปรที่ประกาศ ณ จุดใดก็ได้ในสคริปต์ และย้ายตัวแปรนั้นไปยังบรรทัดแรกของสโคปที่กํากับอยู่อย่างมีประสิทธิภาพก่อนที่จะเรียกใช้สคริปต์ ซึ่งหมายความว่าตัวแปรที่ประกาศโดยใช้ var
จะสามารถอ้างอิงได้ก่อนที่จะมีการประกาศตัวแปรโดยที่ไม่ต้องพบข้อผิดพลาด
hoistedVariable
> undefined
var hoistedVariable;
เนื่องจากมีเพียงการประกาศตัวแปรเท่านั้นที่โฮสต์ ไม่ใช่การเริ่มต้นตัวแปร ระบบจะไม่ยกระดับตัวแปรที่ไม่ได้ประกาศอย่างชัดแจ้งด้วย var
, let
หรือ const
unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined
unhoistedVariable = true;
ดังที่ได้กล่าวไว้ก่อนหน้านี้ ระบบจะกําหนดค่า undefined
ให้กับตัวแปรที่ประกาศไว้แต่ยังไม่ได้เริ่มต้น ลักษณะการทำงานดังกล่าวมีผลกับการประกาศตัวแปรที่ยกระดับด้วยเช่นกัน แต่มีผลเฉพาะกับตัวแปรที่ประกาศโดยใช้ var
เท่านั้น
hoistedVariable
> undefined
var hoistedVariable = 2 + 2;
hoistedVariable\
> 4
ลักษณะการทำงานที่ไม่ตรงไปตรงมานี้ส่วนใหญ่มาจากการตัดสินใจด้านการออกแบบใน JavaScript เวอร์ชันแรกๆ และไม่สามารถเปลี่ยนแปลงได้โดยไม่เสี่ยงที่จะทำให้เว็บไซต์ที่มีอยู่ใช้งานไม่ได้
let
และ const
จัดการลักษณะการทำงานนี้ด้วยการแสดงข้อผิดพลาดเมื่อมีการเข้าถึงตัวแปรก่อนที่จะสร้าง
{
hoistedVariable;
let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization
ข้อผิดพลาดนี้แตกต่างจากข้อผิดพลาด "hoistedVariable is not defined" ที่คุณอาจพบเมื่อพยายามเข้าถึงตัวแปรที่ไม่ได้ประกาศ เนื่องจาก JavaScript ได้ยกระดับตัวแปรแล้ว จึงทราบว่าระบบจะสร้างตัวแปรภายในขอบเขตที่ระบุ อย่างไรก็ตาม แทนที่จะทำให้ตัวแปรนั้นพร้อมใช้งานก่อนการประกาศที่มีค่าเป็น undefined
โปรแกรมล่ามจะแสดงข้อผิดพลาด
ตัวแปรที่ประกาศด้วย let
หรือ const
(หรือ class
) ถือว่าอยู่ใน "เขตตายตามเวลา" ("TDZ") ตั้งแต่จุดเริ่มต้นของบล็อกที่ล้อมรอบจนกว่าจะถึงจุดในโค้ดที่มีการประกาศตัวแปร
เขตเวลาที่ไม่มีสัญญาณทำให้ผู้เขียนเข้าใจลักษณะการทํางานของ let
ได้ง่ายกว่า var
และยังมีส่วนสําคัญต่อการออกแบบ const
ด้วย เนื่องจากค่าคงที่เปลี่ยนแปลงไม่ได้ ค่าคงที่ที่ยกระดับไปยังด้านบนของขอบเขตและกำหนดค่าโดยนัยของ undefined
จึงไม่สามารถเริ่มต้นด้วยค่าที่มีความหมายได้
ทดสอบความเข้าใจ
คุณใช้อักขระประเภทใดขึ้นต้นตัวระบุได้บ้าง
วิธีการใดที่แนะนำในการประกาศตัวแปรที่มีค่าเปลี่ยนแปลงได้ทุกเมื่อ