Statements (Control Flow)

จาวาสคริปต์รองรับชุดคำสั่งขนาดย่อม ซึ่งส่วนใหญ่เป็นคำสั่งควบคุมที่คุณสามารถใช้สร้างปฏิสัมพันธ์ในหน้าเว็บได้หลากหลาย โดยในบทนี้จะกล่าวถึงภาพรวมของคำสั่งเหล่านี้

นิพจน์ก็เป็นคำสั่งแบบหนึ่ง ดูข้อมูลเกี่ยวกับนิพจน์ได้ที่ Expressions and Operators

ใช้เครื่องหมายเซมิโคลอน (;) เพื่อแยกคำสั่งในโปรแกรมจาวาสคริปต์

ดูรายละเอียดของคำสั่งต่างๆในบทนี้ได้ที่ JavaScript Reference

บล็อกคำสั่ง

บล็อกคำสั่ง ใช้เพื่อจัดกลุ่มคำสั่ง โดยจำกัดขอบเขตบล็อกด้วยคู่วงเล็บปีกกา ดังนี้:

{
   statement_1;
   statement_2;
   .
   .
   .
   statement_n;
}

ตัวอย่าง
บล็อกคำสั่ง โดยทั่วไปใช้ร่วมกับคำสั่งควบคุมต่างๆ (เช่น if, for, while)

while (x < 10){
  x++;
}

โดยที่, {  x++; } คือบล็อกคำสั่ง

เรื่องสำคัญ: จาวาสคริปต์ ไม่มี ขอบเขตบล็อก โดยตัวแปรที่ประกาศภายในบล็อกมีขอบเขตอยู่ในฟังก์ชันหรือสคริปต์ที่ครอบบล็อกนั้น และการให้ค่าตัวแปรเหล่านี้มีผลถึงข้างนอกบล็อกนั้นด้วย หรืออธิบายได้ว่า, บล็อกคำสั่งไม่สร้างขอบเขตตัวแปรขึ้น และถึงแม้ว่าจะสามารถใช้บล็อกคำสั่งโดยไม่มีคำสั่งควบคุมได้ คุณก็ไม่ควรทำแบบนั้นในจาวาสคริปต์ เพราะมันไม่ได้ทำงานแบบเดียวกับในภาษาซีหรือจาวาอย่างที่เราคิด ตัวอย่าง เช่น:

var x = 1;
{
  var x = 2;
}
alert(x); // outputs 2

จะได้ค่า 2 เพราะว่าคำสั่ง var x ในบล็อกอยู่ในขอบเขตเดียวกับ var x นอกบล็อก แต่ถ้าเป็นในภาษาซีหรือจาวา,  จะได้ค่าเป็น 1

คำสั่งเงื่อนไข

คำสั่งเงื่อนไข คือชุดคำสั่งที่จะทำงานเมื่อเงื่อนไขที่ระบุเป็นจริง โดยจาวาสคริปต์รองรับคำสั่งเงื่อนไขสองแบบ คือ if...else และ switch

คำสั่ง if...else

ใช้คำสั่ง if เมื่อต้องการให้คำสั่งที่กำหนด ทำงานเมื่อเงื่อนไขตรรกะเป็นจริง (true) และอาจใช้ else ได้ ถ้าต้องการให้อีกคำสั่งทำงานเมื่อเงื่อนไขเป็นเท็จ (false) โดยคำสั่ง if มีรูปแบบการใช้งานดังนี้: 

if (condition)
  statement_1
[else
  statement_2]

โดย condition เป็นนิพจน์ใดๆที่หาค่าได้เป็น true หรือ false (ดูคำอธิบายเรื่องวิธีการหาค่า true และ false ได้ที่ Boolean) ซึ่งถ้า condition มึค่าเป็น true จะทำให้ statement_1 ทำงาน และในทางตรงข้าม, statement_2 จะทำงานแทน โดยที่ statement_1 และ statement_2 สามารถเป็นคำสั่ง if ซ้อนได้

คุณสามารถผสมคำสั่ง โดยใช้ else if เมื่อต้องการทดสอบเงื่อนไขทีละขั้นได้ ดังนี้:

if (condition)
  statement_1
[else if (condition_2)
  statement_2]
...
[else if (condition_n_1)
  statement_n_1]
[else
  statement_n]

ถ้าต้องการให้หลายคำสั่งทำงานในเงื่อนไขเดียวกัน, ให้รวมคำสั่งเข้าด้วยกันในบล็อกคำสั่ง ({ ... }) ซึ่งการใช้บล็อกคำสั่งอยู่เสมอเป็นวิธีการที่ดี โดยเฉพาะเมื่อใช้คำสั่ง if ซ้อนกันหลายชั้น:

if (condition) {
    statement_1_runs_if_condition_is_true
    statement_2_runs_if_condition_is_true
} else {
    statement_3_runs_if_condition_is_false
    statement_4_runs_if_condition_is_false
}
ที่ไม่ควรทำคือ การกำหนดค่าภายในนิพจน์เงื่อนไข, เพราะจากโค้ด อาจทำให้เกิดการสับสนระหว่างการกำหนดค่า กับการเปรียบเทียบค่าได้ ดังตัวอย่าง, ไม่ควรเขียนโค้ดแบบนี้
 
if (x = y) {
  /* do the right thing */
}

ถ้าคุณจำเป็นต้องกำหนดค่าในนิพจน์เงื่อนไข, วิธีที่ใช้กันคือ ใส่วงเล็บครอบไปอีกชั้น เช่นตัวอย่างนี้:

if ((x = y)) {
  /* do the right thing */
}

ค่าต่อไปนี้ เมื่อนำมาหาค่าแล้วจะได้ค่า false :

  • false
  • undefined
  • null
  • 0
  • NaN
  • สตริงว่าง ("")

สำหรับค่าอื่นๆ รวมทั้งอ็อบเจ็กต์ทุกตัว, เมื่อนำมาหาค่าในคำสั่งเงื่อนไข จะได้ค่า true เสมอ

อย่าสับสนกับค่าข้อมูลตรรกะพื้นฐาน true และ false กับค่าที่ได้จากอ็อบเจกต์ Boolean ดังตัวอย่าง

var b = new Boolean(false);
if (b) // this condition evaluates to true

Example
ในตัวอย่างต่อไปนี้, ฟังก์ชัน checkData จะคืนค่า true ถ้าอ็อบเจกต์ threeChar มีข้อความยาวสามอักขระ, นอกจากนั้นจะแสดงคำเตือน และคืนค่า false

function checkData() {
  if (document.form1.threeChar.value.length == 3) {
    return true;
  } else {
    alert("Enter exactly three characters. " +
      document.form1.threeChar.value + " is not valid.");
    return false;
  }
}

คำสั่ง switch

คำสั่ง switch ทำงานโดยนำค่าของนิพจน์มาจับคู่กับค่าที่กำหนด ถ้าตรงกัน, โปรแกรมจะทำงานตามคำสั่งที่เกี่ยวข้อง คำสั่ง switch มีรูปแบบการใช้ดังนี้:

switch (expression) {
   case label_1:
      statements_1
      [break;]
   case label_2:
      statements_2
      [break;]
   ...
   default:
      statements_def
      [break;]
}

เริ่มจากโปรแกรมมองหาประโยค case ที่มีค่าตรงกับค่าจากนิพจน์ (expression) และข้ามไปทำงานที่ตำแหน่งนั้นตามคำสั่งที่กำหนด ถ้าไม่พบค่าที่ตรงกัน, โปรแกรมจะมองหาประโยค default และทำงานที่ตำแหน่งนั้นตามคำสั่งที่กำหนด ถ้าไม่พบประโยค default, โปรแกรมจะทำงานต่อที่ตำแหน่งถัดจากคำสั่ง switch ซึ่งตามหลักการแล้ว, ประโยค default ควรอยู่ท้ายสุด แต่ก็ไม่จำเป็นเสมอไป

คำสั่ง break ที่ใส่ไว้ในประโยค case จะทำให้โปรแกรมหยุดทำงานและออกจากคำสั่ง switch แล้วทำงานต่อที่ตำแหน่งถัดจากคำสั่ง switch แต่ถ้าไม่มี break, โปรแกรมจะทำงานต่อที่คำสั่งถัดไปใน switch

ตัวอย่าง
ในตัวอย่างต่อไปนี้, ถ้า fruttype มีค่าเป็น "Bananas" โปรแกรมจะพบค่าที่ตรงกันในประโยค case "Bananas" และข้ามไปทำงานที่ตำแหน่งนั้น จนถึงคำสั่ง break โปรแกรมก็จะหยุดทำงานแล้วทำงานต่อที่ตำแหน่งถัดจากคำสั่ง switch แต่ถ้าไม่มี break, โปรแกรมจะทำงานต่อที่คำสั่งถัดมาในประโยค case "Cherries" ด้วย

switch (fruittype) {
   case "Oranges":
      document.write("Oranges are $0.59 a pound.<br>");
      break;
   case "Apples":
      document.write("Apples are $0.32 a pound.<br>");
      break;
   case "Bananas":
      document.write("Bananas are $0.48 a pound.<br>");
      break;
   case "Cherries":
      document.write("Cherries are $3.00 a pound.<br>");
      break;
   case "Mangoes":
   case "Papayas":
      document.write("Mangoes and papayas are $2.79 a pound.<br>");
      break;
   default:
      document.write("Sorry, we are out of " + fruittype + ".<br>");
}
document.write("Is there anything else you'd like?<br>");

คำสั่งลูป

คำสั่งลูป คือชุดคำสั่งที่ทำงานซ้ำจนกระทั่งเงื่อนไขที่กำหนดเป็นจริง โดยจาวาสคริปต์รองรับคำสั่งลูป for, do...while, และ while และป้ายชื่อคำสั่ง (ซึ่งไม่ใช่คำสั่งลูป แต่มักใช้คู่กัน) นอกจากนี้, คุณยังสามารถใช้คำสั่ง break และ continue กับคำสั่งลูปได้ด้วย

อีกคำสั่งหนึ่งคือ for...in, เป็นคำสั่งที่ทำงานวนซ้ำเหมือนกัน แต่ใช้กับการจัดการอ็อบเจกต์ ดูเพิ่มเติมที่ Object Manipulation Statements

คำสั่งลูปทั้งหมด มีดังนี้:

คำสั่ง for

คำสั่งลูป for จะทำงานซ้ำจนกระทั่งเงื่อนไขที่กำหนดเป็นเท็จ (false) โดย for ในจาวาสคริปต์ทำงานคล้าย for ในภาษาจาวาและซี ซึ่งมีรูปแบบการใช้งานดังนี้:

for ([initialExpression]; [condition]; [incrementExpression])
   statement

เมื่อคำสั่ง for ทำงาน, สิ่งที่เกิดขึ้นคือ:

  1. ถ้ามีนิพจน์ initialExpression, จะมีการประมวลค่านิพจน์นี้ ซึ่งโดยทั่วไปจะใช้เพื่อกำหนดค่าเริ่มต้นให้กับตัวแปร ตัวเดียวหรือหลายตัว แต่ก็สามารถใช้กับนิพจน์ที่มีความซับซ้อน และใช้ประกาศตัวแปรได้
  2. ทำการประมวลค่านิพจน์ condition, ถ้ามีค่าเป็นจริง (true) คำสั่งในลูปทั้งหมดจะทำงาน แต่ถ้ามีค่าเท็จ (false) ลูป for จะหยุดทำงาน และถ้าไม่มีนิพจน์ condition เลย, ค่าเงื่อนไขนี้จะถูกสมมุติให้เป็นจริง (true)
  3. คำสั่ง statement เริ่มทำงาน, ถ้าต้องการทำงานหลายคำสั่ง ต้องใช้บล็อกคำสั่ง (( ... )) หุ้มอีกชั้น
  4. ถ้ามีนิพจน์ incrementExpression, จะมีการประมวลค่านิพจน์นี้ และกลับไปทำงานที่ขั้นตอนที่ 2

ตัวอย่าง
ฟังก์ชันต่อไปนี้ประกอบด้วยคำสั่ง for ซึ่งใช้นับจำนวนตัวเลือกที่ถูกเลือกในรายการข้อมูล (อ็อบเจกต์ Select ยอมให้เลือกได้หลายค่า) โดยคำสั่ง for ประกาศตัวแปร i และกำหนดค่าเริ่มต้นเป็นศูนย์ จากนั้นจะตรวจสอบว่า i ยังมีค่าน้อยกว่าจำนวนตัวเลือกในอ็อบเจกต์ Select แล้วจึงทำตามคำสั่ง if ที่กำหนด และเพิ่มค่า i ทีละหนึ่งทุกครั้งที่ครบลูป

<script>

function howMany(selectObject) {
   var numberSelected = 0;
   for (var i = 0; i < selectObject.options.length; i++) {
      if (selectObject.options[i].selected)
         numberSelected++;
   }
   return numberSelected;
}

</script>

<form name="selectForm">
   <p>
      <strong>Choose some music types, then click the button below:</strong>
      <br/>
      <select name="musicTypes" multiple="multiple">
         <option selected="selected">R&B</option>
         <option>Jazz</option>
         <option>Blues</option>
         <option>New Age</option>
         <option>Classical</option>
         <option>Opera</option>
      </select>
   </p>
   <p>
      <input type="button" value="How many are selected?"
         onclick="alert ('Number of options selected: ' + howMany(document.selectForm.musicTypes))"/>
   </p>
</form>

คำสั่ง do...while

คำสั่ง do...while จะทำงานซ้ำจนกระทั่งเงื่อนไขที่กำหนดเป็นเท็จ (false) โดยมีรูปแบบการใช้งานดังนี้:

do
   statement
while (condition);

คำสั่ง statement จะทำงานหนึ่งครั้งก่อนที่จะมีการตรวจสอบเงื่อนไข ถ้าต้องการทำงานหลายคำสั่ง ต้องใช้บล็อกคำสั่ง ({ ... }) หุ้มอีกชั้น เมื่อเงื่อนไข condition เป็นจริง (true), คำสั่ง statement จะทำงานอีกครั้ง โดยทุกครั้งที่จบการทำงานจะทำการตรวจสอบเงื่อนไข เมื่อเงื่อนไขเป็นเท็จ (false), การทำงานจะหยุดและข้ามไปทำต่อที่คำสั่งถัดจาก do...while

ตัวอย่าง
ในตัวอย่างต่อไปนี้, ลูป do จะทำงานซ้ำอย่างน้อยหนึ่งครั้ง และทำซ้ำอีกจนกระทั่ง i มีค่าไม่น้อยกว่า 5

do {
   i += 1;
   document.write(i);
} while (i < 5);

คำสั่ง while

คำสั่ง while จะทำงานเมื่อเงื่อนไขที่กำหนดเป็นจริง (true) โดยมีรูปแบบการใช้งานดังนี้:

while (condition)
   statement

ถ้าเงื่อนไขกลายเป็นเท็จ (false), คำสั่งในลูปจะหยุดทำงานและข้ามไปทำงานต่อที่คำสั่งถัดจากลูป

การทดสอบเงื่อนไขจะเกิดขี้นก่อนคำสั่ง statement ในลูปเริ่มทำงาน เมื่อเงื่อนไขเป็นจริง (true), คำสั่ง statement จะทำงาน และเงื่อนไขจะถูกทดสอบอีกครั้ง จนเมื่อเงื่อนไขเป็นเท็จ (false) การทำงานจะหยุดและข้ามไปทำงานต่อที่คำสั่งถัดจาก while

ถ้าต้องการทำงานหลายคำสั่ง, ให้ใช้บล็อกคำสั่ง ({ ... }) หุ้มอีกชั้น

ตัวอย่างที่ 1
ลูป while ต่อไปนี้ จะทำงานซ้ำเมื่อ n ยังน้อยกว่า 3:

n = 0;
x = 0;
while (n < 3) {
   n++;
   x += n;
}

ในแต่ละรอบของการทำซ้ำ, ลูปจะเพิ่มค่า n และบวกค่าให้ x, นั่นคือ x และ n จะมีค่าดังนี้:

  • หลังจากผ่านรอบแรกไป: n = 1 และ x = 1
  • หลังจากผ่านไปสองรอบ: n = 2 และ x = 3
  • หลังจากผ่านไปสามรอบ: n = 3 และ x = 6

หลังจากจบรอบสาม, เงื่อนไขที่ n < 3 ไม่เป็นจริงอีกแล้ว, ลูปจึงหยุดทำงาน

ตัวอย่างที่ 2
เพื่อหลีกเลี่ยงการวนลูปแบบไม่สิ้นสุด, ต้องแน่ใจว่าเงื่อนไขในลูปจะกลายเป็นเท็จ (false) ได้ในที่สุด มิเช่นนั้นลูปจะทำงานไม่หยุด เช่น คำสั่งในลูป while ต่อไปนี้จะทำงานไปตลอดเพราะเงื่อนไขไม่เคยเป็นเท็จ (false)

while (true) {
   alert("Hello, world");
}

ป้ายชื่อคำสั่ง

การกำหนดป้ายชื่อคำสั่ง คือการติดป้ายชื่อที่คำสั่งใดๆเพื่อช่วยให้คุณอ้างถึงมันได้จากที่ต่างๆในโปรแกรม ตัวอย่าง เช่น, คุณสามารถติดป้ายชื่อที่คำสั่งลูป และใช้คำสั่ง break หรือ continue เพื่อให้โปรแกรมหยุดการทำงานและออกจากลูป หรือทำงานต่อที่ลูปนั้น

รูปแบบการติดป้ายชื่อที่คำสั่ง มีวิธีดังนี้:

label :
   statement

โดย label คือป้ายชื่อคำสั่ง ตั้งชื่อตามแบบตัวแปรในจาวาสคริปต์ ซึ่งไม่สามารถใช้คำสงวนได้ โดยคำสั่ง statement ที่กำหนดคู่กับป้ายชื่อ label จะเป็นคำสั่งแบบใดก็ได้

ตัวอย่าง
ในตัวอย่างนี้, markLoop คือป้ายชื่อที่ตั้งให้ลูป while

markLoop:
while (theMark == true) {
   doSomething();
}

คำสั่ง break

ใช้คำสั่ง break เพื่อหยุดการทำงานในลูป, switch, หรือใช้ร่วมกับป้ายชื่อคำสั่ง

  • เมื่อคุณใช้ break โดยไม่ระบุป้ายชื่อคำสั่ง, มันจะหยุดการทำงานของคำสั่งชั้นในสุดของ while, do-while, for, หรือ switch ทันทีและข้ามออกมาทำงานในคำสั่งถัดไป
  • เมื่อคุณใช้ break และระบุป้ายชื่อคำสั่ง, มันจะหยุดการทำงานของคำสั่งตามป้ายชื่อนั้น

รูปแบบของคำสั่ง break เป็นดังนี้:

  1. break;
  2. break label;

รูปแบบแรกจะหยุดการทำงานของลูปในสุด หรือใน switch, ส่วนแบบที่สอง จะหยุดการทำงานของคำสั่งทีี่มีป้ายชื่อ label

ตัวอย่างที่ 1:
ตัวอย่างต่อไปนี้ ทำงานซ้ำตามจำนวนสมาชิกในอาร์เรย์ จนกระทั่งพบตำแหน่งของสมาชิกที่มีค่าเท่ากับ theValue

for (i = 0; i < a.length; i++) {
   if (a[i] == theValue)
      break;
}

ตัวอย่างที่ 2: หยุดทำงานของคำสั่งตามป้ายชื่อที่กำหนด

var x = 0;
var z = 0
labelCancelLoops: while (true) {
    console.log("Outer loops: " + x);
    x += 1;
    z = 1;
    while (true) {
        console.log("Inner loops: " + z);
        z += 1;
        if (z === 10 && x === 10) {
            break labelCancelLoops;
        } else if (z === 10) {
            break;
        }
    }
}

คำสั่ง continue

คำสั่ง continue ใช้เพื่อเริ่มการทำงานใหม่ของคำสั่ง while, do-while, for, หรือที่ป้ายชื่อคำสั่ง:

  • เมื่อคุณใช้ continue โดยไม่ระบุป้ายชื่อคำสั่ง, มันจะหยุดการทำงานรอบปัจจุบันที่ชั้นในสุดของคำสั่ง while, do-while หรือคำสั่ง for และเริ่มทำงานลูปใหม่ในรอบถัดไป ที่ตรงข้ามกับคำสั่ง break คือ continue จะไม่หยุดการทำงานของลูปทั้งหมด โดยในลูป while, มันจะข้ามไปทำงานที่ตำแหน่งเงื่อนไข และในลูป for, มันจะข้ามไปทำงานที่ส่วน increment-expression
  • เมื่อคุณใช้ continue กับป้ายชื่อคำสั่ง, มันจะถูกใช้กับคำสั่งลูปที่มีป้ายชื่อตามที่กำหนด

รูปแบบของคำสั่ง continue เป็นได้ดังนี้:

  1. continue;
  2. continue label;

ตัวอย่างที่ 1
ตัวอย่างต่อไปนี้แสดง ลูป while ที่มีคำสั่ง continue ซึ่งจะทำงานเมื่อ i เป็น 3 นั่นคือ n จะมีค่าเป็น หนึ่ง, สาม, เจ็ด, และสิบสอง

i = 0;
n = 0;
while (i < 5) {
   i++;
   if (i == 3)
      continue;
   n += i;
}

ตัวอย่างที่ 2
โปรแกรมต่อไปนี้ มีคำสั่ง while ติดป้ายชื่อ checkiandj ที่ภายในมีคำสั่ง while ติดป้ายชื่อ checkj เมื่อโปรแกรมทำงานถึงคำสั่ง continue, โปรแกรมจะหยุดการทำงานรอบปัจจุบันของ checkj และเริ่มทำงานในรอบถัดไป โดยทุกครั้งที่ทำงานถึง continue โปรแกรมก็จะกลับไปเริ่มทำงาน checkj รอบใหม่จนกระทั่งได้เงื่อนไขที่เป็นเท็จ (false) ซึ่งทำให้โปรแกรมหลุดออกจากลูป checkj เข้ามาในลูปใหญ่ checkiandj และทำงานต่อจนจบลูป จากนั้น checkiandj ก็ทำงานซ้ำจนได้เงื่อนไขที่เป็นเท็จ (false) ซึ่งทำให้โปรแกรมหลุดออกจากลูป checkiandj และทำงานที่คำสั่งถัดไป

แต่ถ้า continue ระบุป้ายชื่อ checkiandj, โปรแกรมก็จะทำงานต่อที่ส่วนบนสุดของคำสั่ง checkiandj แทน

checkiandj :
   while (i < 4) {
      document.write(i + "<br/>");
      i += 1;
      checkj :
         while (j > 4) {
            document.write(j + "<br/>");
            j -= 1;
            if ((j % 2) == 0)
               continue checkj;
            document.write(j + " is odd.<br/>");
         }
      document.write("i = " + i + "<br/>");
      document.write("j = " + j + "<br/>");
   }

คำสั่งจัดการอ็อบเจกต์

จาวาสคริปต์ใช้คำสั่ง for...in, for each...in, และ with ในการจัดการกับอ็อบเจกต์

คำสั่ง for...in

คำสั่ง for...in จะทำงานซ้ำตามจำนวนคุณสมบัติของอ็อบเจกต์ โดยในแต่ละรอบ,ตัวแปรจะถูกกำหนดให้มีค่าเป็นคุณสมบัติของอ็อบเจกต์ทีละตัว และจาวาสคริปต์จะทำงานตามคำสั่งที่กำหนด จนครบตามจำนวนคุณสมบัติที่ต่างกันทั้งหมด โดยมีรูปแบบต่อไปนี้:

for (variable in object) {
   statements
}

ตัวอย่าง
ฟังก์ชันต่อไปนี้ รับค่าพารามิเตอร์ อ็อบเจกต์และชื่ออ็อบเจกต์ โดยจะทำงานซ้ำตามคุณสมบัติทั้งหมดของอ็อบเจกต์ และคืนค่าสตริงที่แสดงชื่อคุณสมบัติกับค่าของมัน

function dump_props(obj, obj_name) {
   var result = "";
   for (var i in obj) {
      result += obj_name + "." + i + " = " + obj[i] + "<br>";
   }
   result += "<hr>";
   return result;
}

เมื่อใช้กับอ็อบเจกต์ car ที่มีคุณสมบัติ make และ model, จะได้ค่า result ดังนี้:

car.make = Ford
car.model = Mustang

อา์เรย์
แม้ว่าเราอยากจะใช้วิธีนี้เพื่อวนซ้ำตามจำนวนสมาชิกของอ็อบเจกต์อาร์เรย์, แต่เนื่องจากคำสั่ง for...in นอกจากจะทำงานซ้ำตามจำนวนสมาชิกอาร์เรย์แล้ว ยังทำงานซ้ำตามจำนวนคุณสมบัติของอาร์เรย์ด้วย ดังนั้นถ้าคุณแก้ไขอ็อบเจกต์อาร์เรย์ โดยเพิ่มคุณสมบัติหรือเมธอดเข้าไป, คำสั่ง for...in จะทำงานซ้ำด้วยจำนวนครั้งที่รวมจำนวนคุณสมบัติและจำนวนสมาชิกเข้าด้วยกัน ด้วยเหตุนี้, วิธีที่ดีกว่าคือใช้คำสั่ง for แบบปกติ และทำการวนซ้ำด้วยเลขตำแหน่งของสมาชิกในอาร์เรย์

คำสั่ง for each...in

for each...in เป็นคำสั่งลูปที่เริ่มมีใน JavaScript 1.6 มีการทำงานคล้าย for...in แต่ค่าที่วนซ้ำเป็นค่าของคุณสมบัติอ็อบเจกต์, ไม่ใช่ตัวคุณสมบัติ

var sum = 0;
var obj = {prop1: 5, prop2: 13, prop3: 8};
for each (var item in obj) {
  sum += item;
}
print(sum); // prints "26", which is 5+13+8

คำอธิบาย

คำอธิบาย คือข้อความที่ผู้แต่งเขียนไว้เพื่ออธิบายการทำงานของสคริปต์ ซึ่งไม่ถูกอ่านโดยตัวแปลภาษา โดยจาวาสคริปต์รองรับคำอธิบายในแบบภาษาจาวาและซีพลัสพลัสดังนี้:

  • คำอธิบายบรรทัดเดียว ให้เริ่มต้นด้วย //
  • คำอธิบายที่มีหลายบรรทัด ให้นำหน้าด้วย /* และปิดท้ายด้วย */

ตัวอย่าง
ตัวอย่างต่อไปนี้ แสดงการเขียนคำอธิบายทั้งสองแบบ

// This is a single-line comment.

/* This is a multiple-line comment. It can be of any length, and
you can put whatever you want here. */

คำสั่งจัดการข้อผิดพลาด

คุณสามารถสร้างข้อผิดพลาดในโปรแกรม ด้วยการใช้คำสั่ง throw และจัดการมันด้วยคำสั่ง try...catch

คุณยังสามารถใช้ try...catch เพื่อจัดการข้อผิดพลาดของจาวาได้ (แม้ว่าจะมี bug 391642 ก็ตาม) โดยดูข้อมูลเพิ่มเติมได้ที่ Handling Java Exceptions in JavaScript และ JavaScript to Java Communication

ชนิดของข้อผิดพลาด

เราสามารถสร้างข้อผิดพลาดจากอ็อบเจกต์ชนิดใดก็ได้ แต่อย่างไรก็ตาม, อ็อบเจกต์ทุกตัวไม่ได้ถูกสร้างมาให้เท่าเทียมกัน ในกรณีทั่วไปอาจใช้แค่ตัวเลขหรือสตริงแทนข้อผิดพลาดได้ แต่เพิ่อประสิทธิภาพที่ดีกว่า เรามักจะใช้รูปแบบข้อผิดพลาดที่สร้างขึ้นโดยเฉพาะดังนี้:

คำสั่ง throw

ใช้คำสั่ง throw เพื่อสร้างข้อผิดพลาด โดยให้ระบุนิพจน์แทนข้อผิดพลาด คู่กับคำสั่งดังนี้:

throw expression;

คุณอาจสร้างข้อผิดพลาดด้วยนิพจน์แบบใดก็ได้ ไม่ใช่แค่นิพจน์ของข้อมูลแบบใดแบบหนึ่งเท่านั้น ในโค้ดต่อไปนี้แสดงการสร้างข้อผิดพลาดด้วยข้อมูลที่แตกต่างชนิดกัน

throw "Error2";   //String type
throw 42;         //Number type
throw true;       //Boolean type
throw {toString: function() { return "I'm an object!"; } };
Note: คุณสามารถระบุอ็อบเจกต์เมื่อคุณสร้างข้อผิดพลาดขึ้น จากนั้นสามารถอ้างถึงคุณสมบัติของอ็อบเจกต์นั้นได้จากในบล็อกคำสั่ง catch โดยตัวอย่างต่อไปนี้ มีการสร้างอ็อบเจกต์ myUserException ที่มีชนิด UserException และใช้ในคำสั่ง throw
// Create an object type UserException
function UserException (message){
  this.message=message;
  this.name="UserException";
}

// Make the exception convert to a pretty string when used as a string (e.g. by the error console)
UserException.prototype.toString = function (){
  return this.name + ': "' + this.message + '"';
}

// Create an instance of the object type and throw it
throw new UserException("Value too high");

คำสั่ง try...catch

คำสั่ง try...catch กำหนดบล็อกของคำสั่งที่จะทำงาน และกำหนดการตอบสนองต่อข้อผิดพลาดหนึ่งชนิดขึ้นไป โดยเมื่อมีข้อผิดพลาดเกิดขึ้น, คำสั่ง try...catch ก็สามารถจัดการมันได้

คำสั่ง try...catch ประกอบด้วย บล็อก try ที่มีคำสั่งหนึ่งคำสั่งหรือมากกว่า และบล็อก catch มากกว่าหนึ่งหรือไม่มีเลย ในบล็อกนี้จะมีคำสั่งที่ระบุว่าให้ทำอะไรถ้ามีข้อผิดพลาดเกิดขึ้นในบล็อก try นั่นคือคุณต้องการให้คำสั่งในบล็อก try ทำงานสำเร็จ, แต่เมื่อทำไม่สำเร็จ คุณต้องการส่งต่อการทำงานไปที่บล๊อก catch โดยเมื่อคำสั่งใดๆในบล็อก try (หรือในการเรียกใช้ฟังก์ชันจากภายในบล็อก try) สร้างข้อผิดพลาดขึ้น การทำงานของโปรแกรมจะข้ามไปที่บล็อก catch ทันที แต่ถ้าไม่มีข้อผิดพลาดเกิดขึ้นในบล็อก try, โปรแกรมจะข้ามบล็อก catch ไป และจากนั้นบล๊อก finally จะทำงานหลังจากบล็อก try และ catch ทำงานจบแล้ว ก่อนที่จะทำงานในคำสั่งถัดจากคำสั่ง try...catch ต่อไป

ตัวอย่างต่อไปนี้ แสดงการใช้คำสั่ง try...catch โดยตัวอย่างเรียกใช้ฟังก์ชันซึ่งรับชื่อเดือนจากอาร์เรย์ตามค่าเดือนที่ส่งให้ฟังก์ชัน ถ้าค่านี้ไม่สอดคล้องกับจำนวนเดิอน (1-12), จะเกิดข้อผิดพลาดขึ้นเป็นข้อความ "InvalidMonthNo" และคำสั่งในบล็อก catch จะกำหนดค่าให้ ตัวแปร monthName เป็น unknown

function getMonthName (mo) {
    mo=mo-1; // Adjust month number for array index (1=Jan, 12=Dec)
    var months=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul",
          "Aug","Sep","Oct","Nov","Dec");
    if (months[mo] != null) {
       return months[mo]
    } else {
       throw "InvalidMonthNo"          //throw keyword is used here
    }
}

try {// statements to try
    monthName=getMonthName(myMonth) // function could throw exception
}
catch (e) {
    monthName="unknown"
    logMyErrors(e) // pass exception object to error handler
}

บล็อก catch

คุณสามารถใช้บล็อก catch เพื่อจัดการข้อผิดพลาดที่อาจเกิดขึ้นในบล็อก try ได้

catch (catchID) {
  statements
}

บล็อก catch กำหนดชื่อตัวแปร (catchID ในรูปแบบด้านบน) ซึ่งเก็บค่าที่มาจากคำสั่ง throw คุณสามารถใช้ตัวแปรนี้เพื่อดึงข้อมูลเกี่ยวกับข้อผิดพลาดที่เกิดขึ้นได้ โดยจาวาสคริปต์จะสร้างตัวแปรนี้เมื่อบล็อก catch เริ่มทำงาน  และหลังจากที่บล็อก catch ทำงานเสร็จแล้ว ตัวแปรนี้จะหายไป

ตัวอย่าง,  โค้ดต่อไปนี้ทำให้เกิดข้อผิดพลาดขึ้น เมื่อมีข้อผิดพลาดเกิดขึ้น การทำงานจะถูกโอนไปที่บล๊อก catch

try {
   throw "myException" // generates an exception
}
catch (e) {
// statements to handle any exceptions
   logMyErrors(e) // pass exception object to error handler
}

บล็อก finally

บล็อก finally ประกอบด้วย ชุดคำสั่งที่ทำงานหลังจากบล็อก try และ catch ทำงานแล้ว ก่อนที่คำสั่งถัดจาก try...catch จะทำงาน โดยบล็อก finally จะทำงานไม่ว่าจะมีข้อผิดพลาดเกิดขึ้นหรือไม่ ซึ่งคำสั่งในบล็อก finally นี้จะทำงานแม้ว่าบล๊อก catch จะไม่ได้ทำงานก็ตาม

คุณสามารถใช้บล็อก finally เพื่อให้สคริปต์ทำงานจนจบได้แม้จะมีข้อผิดพลาดเกิดขึ้น ตัวอย่าง เช่น, คุณอาจจำเป็นต้องปลด resource เมื่อสคริปต์ทำงานจบ ในตัวอย่างต่อไปนี้ เมื่อเปิดไฟล์และทำงานกับไฟล์ (จาวาสคริปต์บน server ยอมให้คุณเข้าถึงไฟล์ได้) ถ้ามีข้อผิดพลาดเกิดขึ้นตอนเปิดไฟล์ บล็อก finally สามารถปิดไฟล์ได้ก่อนที่สคริปต์จะทำงานผิดพลาด

openMyFile();
try {
    writeMyFile(theData); //This may throw a error
}catch(e){
    handleError(e); // If we got a error we handle it
}finally {
    closeMyFile(); // always close the resource
}

ถ้าบล็อก finally คืนค่ากลับมา, ค่านี้จะกลายเป็นผลลัพธ์จาก try-catch-finally โดยไม่สนใจว่าคำสั่ง return ในบล็อก try และ catch จะคืนค่าอะไร

function f() {
    try {
        alert(0);
        throw "bogus";
    } catch(e) {
        alert(1);
        return true; // this return statement is suspended until finally block has completed
        alert(2); // not reachable
    } finally {
        alert(3);
        return false; // overwrites the previous "return"
        alert(4); // not reachable
    }
    // "return false" is executed now
    
    alert(5); // not reachable
}
f(); // alerts 0, 1, 3; returns false

การซ้อนกันของคำสั่ง try...catch

คุณอาจซ้อนคำสั่ง try...catch เข้าด้วยกันได้ ถ้าคำสั่ง try...catch ชั้นใน ไม่มีบล็อก catch, บล็อก catch ของคำสั่ง try...catch ข้างนอก จะตรวจหาข้อผิดพลาดแทน

การใช้งานอ็อบเจกต์ข้อผิดพลาด

ด้วยชนิดของข้อผิดพลาด, คุณอาจจะใช้คุณสมบัติ 'name' และ 'message' เพื่อให้ได้ข้อความที่สมบูรณ์ขึ้น โดยทั่วไป 'name' จะใช้ระบุชนิดของข้อผิดพลาด (เช่น 'DOMException' หรือ 'Error') และ 'message' จะใช้แสดงข้อความย่อ ที่สั้นกว่าการแปลงอ็อบเจกต์ข้อผิดพลาดให้เป็นสตริง

ถ้าคุณสร้างอ็อบเจกต์ข้อผิดพลาดเอง และต้องการใช้ประโยชน์จากคุณสมบัติต่างๆเหล่านี้ (เช่น บล็อก catch ของคุณไม่แยกแยะระหว่างข้อผิดพลาดของคุณเองกับของระบบ) คุณสามารถใช้ตัวสร้างอ็อบเจกต์ชนิด Error ได้ ดังตัวอย่าง:

function doSomethingErrorProne () {
   if (ourCodeMakesAMistake()) {
      throw (new Error('The message'));
   }
   else {
      doSomethingToGetAJavascriptError();
   }
}
....
try {
   doSomethingErrorProne();
}
catch (e) {
   alert(e.name);// alerts 'Error'
   alert(e.message); // alerts 'The message' or a JavaScript error message)
}

Document Tags and Contributors

 ผู้มีส่วนร่วมกับหน้านี้: Zarazi
 อัปเดตล่าสุดโดย: Zarazi,