การเกิดข้อผิดพลาด
เวลาที่โปรแกรมรันไป หากเกิดข้อผิดพลาดโปรแกรมก็จะหยุดลงทันที ไม่มีการทำอะไรต่อ
ทิ้งไว้เพียงข้อความที่อธิบายว่าเกิดอะไรขึ้น
หากรันผ่านเบราว์เซอร์เราจะเห็นข้อผิดพลาดนั้นได้ก็ต่อเมื่อดูในคอนโซล
ตัวอย่าง
a += 0;
alert(a);
แบบนี้เมื่อโปรแกรมไปถึงบรรทัด a += 0 จะขึ้นในคอนโซลว่า
ReferenceError: a is not defined
นั่นเพราะว่า a ไม่ได้ถูกประกาศไว้ก่อน แต่กลับเรียกใช้ จึงเกิดข้อผิดพลาดขึ้น
หลังจากนั้นโปรแกรมก็ไม่รันต่อ บรรทัด alert(a) ก็จะไม่ทำงาน
เวลาขึ้นข้อผิดพลาดจะขึ้นมาในลักษณะที่ว่า
ชนิดข้อผิดพลาด: คำอธิบาย
ชนิดของข้อผิดพลาด
มีความผิดพลาดหลายแบบที่อาจเกิดขึ้น อย่างในตัวอย่างที่แล้วนั้นเรียกว่าเป็น
ReferenceError
คือข้อผิดพลาดที่เกิดขึ้นเมื่อเมื่อได้ประกาศตัวแปรเอาไว้ก่อนแต่กลับจะเรียกใช้
ในจาวาสคริปต์แบ่งความผิดพลาดออกเป็นดังนี้
RangeError |
ค่าไม่ได้อยู่ในขอบเขตที่ควรจะเป็น |
ReferenceError |
พยายามจะเรียกใช้ตัวแปรที่ไม่ได้ประกาศไว้ |
SyntaxError |
ข้อผิดพลาดทางวากยสัมพันธ์ |
TypeError |
ชนิดของข้อมูลไม่ตรงกับที่ควรเป็น |
URIError |
URI ไม่ถูกต้อง |
TypeError อาจเกิดขึ้นในกรณีที่ได้รับข้อมูลที่ไม่ถูกชนิด เช่นพยายามจะเรียกใช้
() กับข้อมูลที่ไม่ใช่ฟังก์ชัน
Math() // ได้ TypeError: Math is not a function
RangeError เกิดขึ้นเมื่อขอบเขตของค่าที่ป้อนเข้าไปไม่ตรงกับที่ฟังก์ชันต้องการ
เช่น .toFixed ค่าต้องไม่เกิน 100 พอป้อนไป 110 จะเกิดข้อผิดพลาด
(1).toFixed(110); // ได้ RangeError: toFixed() digits argument must be between 0 and 100 at Number.toFixed (<anonymous>)
SyntaxError เกิดขึ้นเมื่อเขียนไม่ถูกไวยากรณ์
1+; // ได้ SyntaxError: Unexpected token ;
URIError เกิดขึ้นเมื่อใช้คำสั่งเช่น decodeURI แล้วมีตัวหนังสือที่ไม่ถูกต้อง
decodeURI("%"); // ได้ URIError: URI malformed at decodeURI (<anonymous>)
ออบเจ็กต์ของข้อผิดพลาด
ข้อผิดพลาดแต่ละแบบนี้เป็นออบเจ็กต์ชนิดหนึ่ง สามารถหยิบจับได้ในโปรแกรม
เหมือนออบเจ็กต์ทั่วไป
alert(typeof SyntaxError); // ได้ object
สามารถใช้เป็นคอนสตรักเตอร์สร้างข้อผิดพลาดขึ้น โดยใส่ข้อความผิดพลาดไว้
var err = new SyntaxError("คุณใช้ภาษาไม่ถูกต้อง");
alert(err); // ได้ SyntaxError: คุณใช้ภาษาไม่ถูกต้อง
ออบเจ็กต์นี้มีพรอเพอร์ตี name คือชื่อชนิดของความผิดพลาด และ message
คือข้อความอธิบายที่เราใส่ลงไป
alert(err.name); // ได้ SyntaxError
alert(err.message); // ได้ คุณใช้ภาษาไม่ถูกต้อง
นอกจากนี้ยังมี Error เฉยๆ
คือข้อผิดพลาดที่ไม่ได้ระบุเจาะจงว่าเป็นข้อผิดพลาดแบบไหน
ออบเจ็กต์ของข้อผิดพลาดเหล่านี้สามารถนำมาใช้เพื่อสร้างความผิดพลาดใหม่ขึ้นเองตามเงื่อนไขที่ต้องการได้
การสร้างความผิดพลาดขึ้นเอง
ไม่ใช่ว่าทุกครั้งที่เกิดข้อผิดพลาดแล้วจะขึ้นเตือน Error
แบบต่างๆนั้นขึ้นมาแล้วทำให้โปรแกรมหยุด
ข้อผิดพลาดบางอย่างนั้นแค่มาจากการที่โปรแกรมทำงานไม่ได้เป็นไปตามดั่งที่คาดไว้
แต่ไม่ถือเป็นข้อผิดพลาดสำหรับจาวาสคริปต์
ที่จริงในจาวาสคริปต์นั้นโอกาสเกิดข้อผิดพลาดจนทำให้โปรแกรมหยุดชะงักนั้นทีค่อนข้างน้อย
เพราะมีความยืดหยุ่นเรื่องชนิดข้อมูล
คือไม่ว่าข้อมูลชนิดไหนก็นำมาบวกลบคูณหารกันได้
โดยจะถูกเปลี่ยนเป็นชนิดที่เหมาะสมให้โดยอัตโนมัติ
นี่อาจฟังดูเหมือนเป็นเรื่องสะดวก
แต่ก็ทำให้เกิดข้อผิดพลาดที่ไม่พึงประสงค์โดยไม่รู้ตัว
เพราะมันไม่มีการเตือนข้อผิดพลาด
เช่นเผลอใส่สายอักขระตัวเลข แทนที่จะเป็นข้อมูลชนิดตัวเลขจริงๆ
alert(11+"22") // ได้ 1122
ถ้าเป็นในภาษาอื่น ทำแบบนี้จะเกิดข้อผิดพลาดจนโปรแกรมหยุดชะงักทันที
แต่ในจาวาสคริปต์ เลข 11 จะถูกแปลงเป็นสายอักขระ "11" แล้วนำไปบวกกัน
กลายเป็นต่อกัน แทนที่จะเป็นการบวกแบบคณิตศาสตร์
จึงกลายเป็นโปรแกรมไม่ได้หยุดชะงัก แต่ทำงานต่อไปโดยให้ผลผิดพลาดแทน
ถ้าจะเป็นแบบนี้สู้ให้โปรแกรมหยุดไปเลยดีกว่า
เราจะได้รู้ว่ามีปัญหาแล้วมาแก้ไข
กรณีแบบนี้เราสามารถสร้างข้อผิดพลาดขึ้นมาเองได้ โดยใช้คำสั่ง throw
if (เงื่อนไขที่ไม่พึงประสงค์) {
throw ออบเจ็กต์ของความผิดพลาด
}
ตัวอย่างเช่น
var a = 12;
var b = "43";
if (typeof a != "number" || typeof b != "number") {
throw new Error("a และ b ต้องเป็นตัวเลขทั้งคู่");
}
alert(a + b);
แบบนี้เมื่อ a หรือ b
มีตัวใดตัวหนึ่งไม่ใช่ข้อมูลชนิดตัวเลขก็จะมีข้อผิดพลาดขึ้นมาว่า
Error: a และ b ต้องเป็นตัวเลขทั้งคู่
แล้วโปรแกรมก็จะหยุดไป ไม่มีการทำ
alert(a + b)
ต่อ
ด้วยการทำแบบนี้ เราสามารถกำหนดเงื่อนไขที่ทำให้เกิดข้อผิดพลาดขึ้นเองได้
ในตัวอย่างนี้ใช้แค่ Error ธรรมดา แต่นอกจากนั้นแล้ว ยังสามารถใช้ RangeError,
TypeError หรือ Error ชนิดอื่นๆที่มีอยู่ตามที่เหมาะได้
ที่จริงชนิดของ Error ที่ใส่ไปไม่ได้มีผลใดๆ
แต่เป็นเหมือนตัวช่วยแบ่งหมวดคร่าวๆได้
อย่างกรณีนี้จริงๆอาจเข้าข่าย TypeError
เพราะเป็นการใส่ข้อมูลผิดชนิดจากที่ควรจะเป็น
การสร้างข้อยกเว้นเมื่อเจอข้อผิดพลาดด้วย try catch
ข้อผิดพลาดเป็นสิ่งที่เกิดขึ้นได้ในโปรแกรมอยู่เสมออยู่แล้ว
แต่หากเราสามารถคาดการณ์ได้ว่าจะเกิดข้อผิดพลาดแบบไหน
เราก็สามารถสร้างวิธีรับมือได้
เพื่อไม่ให้โปรแกรมต้องหยุดชะงักไปเลยเมื่อเจอข้อผิดพลาด
สามารถทำได้โดยใช้โครงสร้าง try catch
try {
คำสั่งที่อาจเกิดข้อผิดพลาด
}
catch {
สิ่งที่จะให้ทำเมื่อเกิดข้อผิดพลาด
}
เมื่อเขียนคำสั่งต่างๆที่คิดว่าอาจมีข้อผิดพลาดไว้ในวงเล็บปีกกาหลัง try
แบบนี้ต่อให้เกิดข้อผิดพลาดขึ้นมาโปรแกรมก็จะไม่หยุด แต่จะไปทำสิ่งที่อยู่ใน
catch ต่อ
หากเราไม่ได้มีสิ่งที่ต้องการทำก็อาจไม่เขียนอะไรลงใน catch เลยก็ได้
แต่ยังไงก็ต้องใส่วงเล็บปีกกาเปล่าไว้ จะละ catch ไม่ได้
try {
คำสั่งที่อาจเกิดข้อผิดพลาด
} catch {}
ตัวอย่าง
var a = 101;
try {
alert(a.toFixed(a));
}
catch {
alert("มีบางอย่างผิดพลาด");
}
เพียงแต่ว่าวิธีนี้ไม่สามารถใช้รับมือ SyntaxError ได้ เพราะหากมี
โปรแกรมจะตรวจเจอตั้งแต่แรกแล้ว ไม่ปล่อยให้รันออกมาได้
try {
1a
} catch {}
ได้
SyntaxError: identifier starts immediately after numeric literal
การเอาข้อผิดพลาดมาแสดงใน catch
ถ้าต้องการจะเอาค่าความผิดพลาดที่เกิดขึ้นมาใช้ด้วยให้ใส่วงเล็บไว้ข้างหลัง catch
แล้วใส่ชื่อตัวแปรที่จะแทนออบเจ็กต์ความผิดพลาด
try {
คำสั่งที่อาจเกิดข้อผิดพลาด
}
catch (พารามิเตอร์) {
สิ่งที่จะให้ทำเมื่อเกิดข้อผิดพลาด
}
เช่น หากให้ต้องการแค่เตือนข้อผิดพลาดที่เกิดขึ้นออกมา
try {
alert(araina);
}
catch (e) {
alert("มีข้อผิดพลาด... " + e);
}
ได้ข้อความว่า
มีข้อผิดพลาด... ReferenceError: araina is not defined
หากต้องการแยกเอาส่วนชื่อของความผิดพลาดกับส่วนข้อความออกจากกันก็ให้ดูค่าที่พรอเพอร์ตี
name กับ message
try {
alert(araikan);
}
catch (e) {
alert("เจอ " + e.name + '\nว่า "' + e.message + '"');
}
ได้ข้อความว่า
เจอ ReferenceError
ว่า "araikan is not defined"
ใช้ throw ใน catch
ปกติเมื่อใช้ try catch แบบนี้โปรแกรมก็จะทำงานต่อไปโดยไม่หยุดแม้จะเจอข้อผิดพลาด
แต่บางครั้งเราก็อาจจะยังอยากให้เกิดข้อผิดพลาดแล้วโปรแกรมหยุดไปตามปกติ
แต่อย่างน้อยก่อนโปรแกรมจะหยุดได้ทำอะไรบางอย่างก่อน กรณีแบบนี้อาจใส่ throw ลงใน
catch
เช่น
try {
alert(arainia);
}
catch (e) {
alert("มีข้อผิดพลาดบางอย่างเกิดขึ้นเสียแล้วสิ... ");
throw e;
}
แบบนี้จะมีกล่องข้อความขึ้นมาเตือน แล้วสุดท้ายก็ขึ้นข้อผิดพลาด ReferenceError
ขึ้นในที่สุดเหมือนกับเมื่อไม่ใส่ try catch
แต่จะต่างกันตรงที่อย่างน้อยก็มีข้อความขึ้นมาเตือนก่อนว่าโปรแกรมผิดพลาดตรงไหนก่อนจะหยุด
เลือกจัดการเฉพาะข้อผิดพลาดบางอย่าง
ข้อผิดพลาดมีอยู่หลายแบบ
แต่บางทีเราอาจจะต้องการสร้างข้อยกเว้นต่อเมื่อเจอข้อผิดพลาดแค่บางอย่าง
ส่วนบางอย่างก็ให้โปรแกรมหยุดไปตามปกติ
แบบนี้ก็อาจใช้ try catch ร่วมกับ throw
โดยตรวจดูว่าความผิดพลาดแล้วเลือกจัดการตามชนิดของความผิดพลาด เช่น
try {
alert(araikannia);
}
catch (e) {
if (e.name == "ReferenceError") {
alert("เจอ " + e.name + " ไม่เป็นไร ไปต่อเถอะ");
}
else {
throw e;
}
}
แบบนี้ถ้าเจอ ReferenceError โปรแกรมก็จะไม่หยุด แค่ขึ้นกล่องข้อความเตือน
แต่ถ้าเจอข้อผิดพลาดชนิดอื่นโปรแกรมก็จะหยุดแล้วขึ้นเตือนข้อผิดพลาดในคอนโซลตามปกติ