φυβλαςのβλογ
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)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

月別記事

2025年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

もっと前の記事

ไทย

日本語

中文