φυβλαςのβλογ
phyblas的博客



javascript เบื้องต้น บทที่ ๑๘: การจัดการกับข้อผิดพลาด
เขียนเมื่อ 2019/07/31 23:29
แก้ไขล่าสุด 2024/03/28 23:05


การเกิดข้อผิดพลาด

เวลาที่โปรแกรมรันไป หากเกิดข้อผิดพลาดโปรแกรมก็จะหยุดลงทันที ไม่มีการทำอะไรต่อ ทิ้งไว้เพียงข้อความที่อธิบายว่าเกิดอะไรขึ้น

หากรันผ่านเบราว์เซอร์เราจะเห็นข้อผิดพลาดนั้นได้ก็ต่อเมื่อดูในคอนโซล

ตัวอย่าง
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 โปรแกรมก็จะไม่หยุด แค่ขึ้นกล่องข้อความเตือน แต่ถ้าเจอข้อผิดพลาดชนิดอื่นโปรแกรมก็จะหยุดแล้วขึ้นเตือนข้อผิดพลาดในคอนโซลตามปกติ




-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> javascript

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

目录

从日本来的名言
模块
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
机器学习
-- 神经网络
javascript
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  查看日志

  推荐日志

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ