Exceptions และ Error ในภาษา JavaScript

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับการจัดการข้อผิดพลาดในภาษา JavaScript ที่เรียกว่า Exception handling มันเป็นวิธีที่จะทำให้โปรแกรมไม่หยุดทำงานและยังสามารถทำงานต่อไปนี้ นอกข้อนี้เราจะพูดถึงข้อผิดพลาดมาตฐานในภาษา JavaScript นี่เป็นเนื้อหาในบทนี้

  • Exception คืออะไร
  • การใช้งานคำสั่ง try catch
  • การ throw ข้อผิดพลาด
  • การใช้งานคำสั่ง finally
  • การสร้างคสาส Error แบบกำหนดเอง
  • Standard error ในภาษา JavaScript

Exception คืออะไร

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

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

noFunction();
console.log("Success");

และนี่เป็นผลลัพธ์การทำงานของโปรแกรม เมื่อโค้ดนี้ถูกรัน

noFunction();
^
ReferenceError: noFunction is not defined

ในการเรียกใช้งานฟังก์ชัน noFunction นั้นจะทำให้เกิดข้อผิดพลาดขึ้น เนื่องจากฟังก์ชันดังกล่าวยังไม่ได้ถูกประกาศ นั่นส่งผลให้โปรแกรมหยุดทำงาน และแสดงผลเกี่ยวกับข้อผิดพลาดที่เกิดขึ้นออกมาแทน นั่นส่งผลให้คำสั่งที่เหลือ เช่น console.log จะไม่ถูกทำงาน

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

การใช้งานคำสั่ง try catch

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

try {
    // Try to do something that may cause errors
} catch (error) {
    // Handing errors
}

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

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

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

try_catch.js
try {
    noFunction();
} catch (error) {
    console.log("Error name: " + error.name);
    console.log("Error message: " + error.message);
}

console.log("Success");

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

console.log("Error name: " + error.name);
console.log("Error message: " + error.message);

โดยทั่วไปแล้วออบเจ็คข้อผิดพลาดในภาษา JavaScript นั้นเป็นออบเจ็คจากคลาส Error ที่มี Property name และ message ที่สามารถใช้รับเอาชื่อและคำอธิบายเกี่ยวกับข้อผิดพลาดได้ ในตัวอย่างนี้ วิธีที่เราจัดการกับข้อผิดพลาดก็คือแสดงรายละเอียดของข้อผิดพลาดที่เกิดขึ้น

console.log("Success");

เมื่อจบการทำงานของบล็อคคำสั่ง try catch โปรแกรมทำงานคำสั่งที่เหลือนอกบล็อคต่อไป ในกรณีนี้คือการแสดงข้อความออกทางหน้าจอ

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

โดยทั่วไปแล้วข้อผิดพลาดที่เกิดขึ้นในภาษา JavaScript นั้นเป็นข้อผิดพลาดมาตรฐานของภาษา ซึ่งมันเกิดขึ้นอัตโนมัติเมื่อ JavaScript engine ไม่สามารถจัดการกับการทำงานบางอย่างได้ ในตัวอย่างก่อนหน้า การเรียกใช้ฟังก์ชันที่ไม่มีอยู่ทำให้เกิดข้อผิดพลาด ReferenceError ขึ้น ซึ่งนี่เป็นข้อผิดพลาดมาตรฐานของภาษา

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

throw expression;

ในการใช้งานคำสั่ง throw จะตามด้วย expression ซึ่งเป็นออบเจ็คของข้อผิดพลาดที่จะถูกส่งไปยังบล็อค catch เมื่อมีการกำหนด ซึ่งมันสามารถเป็นค่าใดๆ ในภาษา JavaScript แต่โดยทั่วไปแล้วมักจะเป็นออบเจ็คจากคลาส Error หรือออบเจ็คจากคลาสที่สืบทอดมาจากคลาส Error

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

throw_error.js
let a = 10;
let b = 0;

if (b == 0) {
    throw new Error("Cannot be divided by Zero");
}

console.log(`${a} / ${b} = ${a / b}`);

นี่เป็นผลลัพธ์การทำงาของโปรแกรม

    throw new Error("Cannot be divided by Zero");
    ^
Error: Cannot be divided by Zero

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

throw new Error("Cannot be divided by Zero");

คำสั่ง throw จะทำให้เกิดข้อผิดพลาดขึ้น เราสร้างออบเจ็คจากคลาส Error ซึ่งเป็นออบเจ็คของข้อผิดพลาดในครั้งนี้ และเราสามารถกำหนดข้อความเกี่ยวกับข้อผิดพลาดที่ต้องการได้ผ่านทางคอนสรัตเตอร์ของคลาส

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

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

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

factorial.js
function factorial(n) {
    if (n < 0) {
        throw new Error("Number must not negative to find factorial");
    }
    if (n > 15) {
        throw new Error("Number is too large to find factorial");
    }
    let fac = 1;
    for (let i = 1; i <= n; i++) {
        fac *= i;
    }
    return fac;
}

let numbers = [3, 5, -1, 20];
for (let num of numbers) {
    try {
        console.log(`${num}! = ${factorial(num)}`);
    } catch (error) {
        console.log(error.message);
    }
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

3! = 6
5! = 120
Number must not negative to find factorial
Number is too large to find factorial

ในตัวอย่างนี้ แสดงวิธีการทำให้เกิดข้อผิดพลาดด้วยคำสั่ง throw โดยฟังก์ชัน factorial ซึ่งเป็นฟังก์ชันสำหรับหาค่า Factorial ของตัวเลข โดยค่า Factorial ของตัวเลขจำนวนเต็ม n หรือ n! นั้นคือผลลัพธ์จากการคูณกันของตัวเลขตั้งแต่ 1 ถึง n ยกเว้น 0! ที่มีค่าเป็น 1

if (n < 0) {
    throw new Error("Number must not negative to find factorial");
}
if (n > 15) {
    throw new Error("Number is too large to find factorial");
}

เนื่องจากการหาค่า Factorial จะทำกับตัวเลขจำนวนเต็มบวกและศูนย์เท่านั้น ดังนั้นเมื่อค่าที่่ส่งเข้ามาน้อยกว่า 0 เราทำให้เกิดข้อผิดพลาดด้วยคำสั่ง throw และนอกจากนี้ตัวเลขสูงสุดที่ส่งเข้ามาจะต้องไม่เกิน 15 ด้วย นี่เพื่อเป็นสิ่งที่จะยืนยันว่าในการใช้งานฟังก์ชันจะต้องใช้กับตัวเลขที่กำหนดเท่านั้น นั่นก็คือ 0 - 15 นั่นเอง

let numbers = [3, 5, -1, 20];
for (let num of numbers) {
    try {
        console.log(`${num}! = ${factorial(num)}`);
    } catch (error) {
        console.log(error.message);
    }
}

ในการใช้งานฟังก์ชัน factorial เราควรจะตรวจสอบการทำงานด้วยคำสั่ง try catch เพื่อให้แน่ใจว่าเมื่อเกิดข้อผิดพลาดเกิดขึ้น โปรแกรมจะจัดการกับมันและทำงานต่อไปได้ ในกรณีนี้เมื่อเกิดข้อผิดพลาดขึ้นสำหรับพารามิเตอร์ -1 และ 20 เราได้แสดงข้อความเกียวกับข้อผิดพลาดจาก error.message

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

try_catch2.js
let select = 3;

try {
    switch (select) {
        case 1:
            console.log(foo);
            break;
        case 2:
            noFunction();
            break;
        case 3:
            throw new Error("This is my error");
        case 4:
            throw new RangeError("Range error");
    }
} catch (error) {
    if (error instanceof ReferenceError) {
        console.log("Use undefined variable or function");
    } else if (error instanceof Error) {
        console.log(error.message);
    } else if (error instanceof RangeError) {
        console.log("Range error occured");
    } else {
        throw error
    }
}

ในตัวอย่าง เป็นการจำลองโปรแกรมที่สามารถทำให้เกิดข้อผิดพลาดประเภทต่างๆ ขึ้นได้ในบล็อคคำสั่ง try เราสามารถเลือกได้ว่าต้องการให้ข้อผิดพลาดใดเกิดขึ้นโดยการกำหนดค่า 1 - 3 ในตัวแปร select ไม่ว่าข้อผิดพลาดประเภทใดจะเกิดขึ้น คำสั่ง try สามารถตรวจจับได้ทั้งหมดและส่งต่อการทำงานไปยังบล็อคของคำสั่ง catch พร้อมกับออบเจ็ค error ของข้อผิดพลาดดังกล่าว

if (error instanceof ReferenceError) {
    console.log("Use undefined variable or function");
} else if (error instanceof Error) {
    console.log(error.message);
} else if (error instanceof RangeError) {
    console.log("Range error occured");
} else {
    throw error
}

เมื่อข้อผิดพลาดในตัวแปร error สามารถเป็นได้หลายประเภท เราสามารถใช้ตัวดำเนินการ instanceof สำหรับตรวจสอบประเภทของข้อผิดพลาด เพื่อจัดการกับข้อผิดพลาดแต่ละประเภทในวิธีที่เหมาะสมได้ต่อไป

throw error

และในบล็อคของคำสั่ง else เราสามารถ throw ข้อผิดพลาดในบล็อคของคำสั่ง catch ได้ นั่นจะทำให้ข้อผิดพลาดนี้ถูกตรวจจับในบล็อคของคำสั่ง try ที่อยู่สูงกว่า (ถ้าหากมี) มันเป็นวิธีที่ดีที่เราควรจะจัดการเพียงข้อผิดพลาดที่รู้จักเท่านั้น ในกรณีที่ไม่รู้จักการทำการ rethrow มัน

การใช้งานคำสั่ง finally

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

try {
    // Do something
} catch (error) {
    // Handing error
} finally {
    // Always execute this block
}

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

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

ในตัวอย่างนี้แสดงการใช้งานคำสั่ง finally ในภาษา JavaScript สำหรับการเรียกใช้งานเมธอดที่ไม่มีอยู่บนออบเจ็ค

let user = {
    id: 1,
    name: "Metin"
};

function sayHi(user) {
    console.log(`Hi ${user.name}!`);
}

try {
    user.sayHi();
} catch (error) {
    console.log(error.message);
    sayHi(user);
} finally {
    console.log("Method has been called");
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

user.sayHi is not a function
Hi Metin!
Method has been called

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

console.log(error.message);
sayHi(user);

ในบล็อคของคำสั่ง catch เราจัดการข้อผิดพลาดโดยการเรียกใช้งานฟังก์ชัน sayHi เพื่อแสดงชื่อในออบเจ็คแทน นี่เป็นวิธีที่เราแก้ปัญหาเมื่อเมธอด sayHi ไม่มีอยู่บนออบเจ็ค user นั่นหมายความว่าเมธอดถูกเรียกใช้สำเร็จเสมอ ไม่วิธีใดก็วิธีหนึ่ง

ในบล็อคของคำสัง finally เราสามารถกำหนดการทำงานเพื่อให้ทำงานเสมอไม่ว่าจะเกิดข้อผิดพลาดหรือไม่ นั่นเป็นเพราะว่าเราได้จัดการการเรียกใช้เมธอดในบล็อคของคำสั่ง catch แล้ว ดังนั้นเราแสดงข้อความว่าเมธอดถูกเรียกใช้สำเร็จ

console.log("Method has been called");

ขอบเขตตัวแปร: คำสั่ง try catch และ finally มีขอบเขตตัวแปรเป็นของมันเอง นั่นหมายความว่าตัวแปรที่ประกาศภายในบล็อคจะสามารถเข้าถึงได้จากโค้ดภายในบล็อค หรือบล็อคที่อยู่ภายในมันเท่านั้น

การสร้างคสาส Error แบบกำหนดเอง

ในตัวอย่างนี้จะเป็นการสร้างคลาสข้อผิดพลาดแบบกำหนดเอง ทุกข้อผิดพลาดที่เกิดขึ้นในภาษา JavaScript นั้นเป็นออบเจ็คจากคลาส Error ซึ่งคลาสนี้มี Property และเมธอดพื้นฐานที่สำคัญที่อธิบายเกี่ยวกับข้อผิดพลาด

ในภาษา JavaScript เราสามารถสร้างคลาสข้อผิดพลาดของเราเองได้โดยการสืบทอดจากคลาส Error นี่จะทำให้เราสามารถเข้าถึง Property และเมธอดพื้นฐานเกี่ยวกับข้อผิดพลาดได้ ในขณะที่ยังสามารถเพิ่มการทำงานบางอย่างของเราเองเข้ามา

นี่เป็นตัวอย่างของการสร้างคลาสข้อผิดพลาดสำหรับจัดการกับการเข้าสู่ระบบที่ไม่ถูกต้อง

login.js
class LoginError extends Error {

    constructor(username, password) {
        super("Invalid username or password");
        this.name = "LoginError";
        this.username = username;
        this.password = password;
    }

    info() {
        console.log("Login failed with");
        console.log("Username: " + this.username);
        console.log("Password: " + "*".repeat(this.password.length));
    }

    log() {
        // Maybe to log invalid attempt to logging service
        console.log("Send log to logging service...");
    }
}

let username = "metin";
let password = "1234";

try {
    if (username == "metin" && password == "secret") {
        console.log("Login success!");
    } else {
        throw new LoginError(username, password);
    }
} catch (error) {
    console.log(error.toString());
    error.info();
    error.log();
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

LoginError: Invalid username or password
Login failed with
Username: metin
Password: ****
Send log to logging service...

ในตัวอย่าง เราได้สร้างคลาสข้อผิดพลาด LoginError ซึ่งเป็นคลาสของข้อผิดพลาดที่จะถูก throw เมื่อการเข้าสู่ระบบไม่ประสบความสำเร็จ คลาสนี้สืบทอดมาจากคลาส Error ซึ่งเป็นคลาสข้อผิดพลาดของภาษา JavaScript

constructor(username, password) {
    super("Invalid username or password");
    this.name = "LoginError";
    this.username = username;
    this.password = password;
}

คอนสตรัคเตอร์ของคลาสรับค่าสองพารามิเตอร์ username และ password ที่ทำให้เกิดข้อผิดพลาดขึ้น เราเรียกใช้งานคอนสตรัคเตอร์ของคลาส Error เพื่อกำหนดคำอธิบายข้อผิดพลาดใหม่ และเปลี่ยนชื่อข้อผิดพลาดเป็น "LoginError" และกำหนด Property ให้กับคลาสจากพารามิเตอร์ที่รับเข้ามา

info() {
    console.log("Login failed with");
    console.log("Username: " + this.username);
    console.log("Password: " + "*".repeat(this.password.length));
}

log() {
    // Maybe to log invalid attempt to logging service
    console.log("Send log to logging service...");
}

ภายในคลาสเราได้สร้างเมธอดเพิ่มเติมสองเมธอด เมธอด info ใช้แสดงรายละเอียดเกี่ยวกับข้อผิดพลาด และเมธอด log นั้นเป็นเมธอดที่จำลองการเก็บบักทึกการเข้าสู่ระบบที่ล้มเหลวไปยัง ยกตัวอย่างเช่น Service สำหรับการเก็บ Log

throw new LoginError(username, password);

ในบล็อคของคำสั่ง try เราได้จำลองการทำงานเพื่อให้เกิดข้อผิดพลาดขึ้น โดยกำหนดให้ชื่อผู้ใช้และรหัสผ่านผิด และทำการ throw ข้อผิดพลาด โดยการสร้างออบเจ็คข้อผิดพลาดจากคลาส LoginError โดยส่งชื่อผู้ใช้และรหัสผ่านเข้าไป

...
} catch (error) {
    console.log(error.toString());
    error.info();
    error.log();
}

จากนั้นในบล็อคของคำสั่ง catch เป็นการจัดการข้อผิดพลาดที่เกิดขึ้นตามปกติ แต่ในตอนนี้เราสามารถเรียกใช้งานเมธอดที่เราสร้างขึ้นได้ เนื่องจากมันเป็นออบเจ็คจากคลาส LoginError ที่ได้ถูก throw มา สังเกตว่าเรายังคงสามารถเรียกใช้เมธอด toString ซึ่งเป็นเมธอดจากคลาส Error ที่สืบทอดมาได้

คุณสามารถสร้างคลาสข้อผิดพลาดโดยไม่สืบทอดจากคลาสข้อผิดพลาดมาตฐานของภาษาได้ แต่คุณจะสูญเสียการเข้าถึง Property และเมธอดพื้นฐานที่สำคัญ โดยทั่วไปแล้วข้อปฏิบัติในการออกแบบคลาสข้อผิดพลาดควรมี Property name และ message และเมธอด toString ซึ่งคุณจะต้องทำทั้งหมดนี้ด้วยตัวเอง และนั่นเป็นวิธีที่ไม่แนะนำ

Standard error ในภาษา JavaScript

เมื่อเกิดข้อผิดพลาดขึ้นในภาษา JavaScript โปรแกรมจะทำการ throw ข้อผิดพลาดโดยข้อผิดพลาดเหล่านั้นเป็นออบเจ็คจากคลาส Error หรือคลาสย่อยของมัน ซึ่งคลาสเหล่านี้ประกอบไปด้วย Property เกี่ยวกับข้อผิดพลาดที่เกิดขึ้นที่เราสามารถเรียกดูได้ ดังนี้

  • message: ข้อความอธิบายข้อผิดพลาดที่เกิดขึ้น
  • name: ชื่อของข้อผิดพลาดที่เกิดขึ้น โดยทั่วแล้วมักจะเป็นชื่อของคลาส
  • fileName: ไฟล์ที่โปรแกรมรันอยู่ในขณะที่เกิดข้อผิดพลาดขึ้น
  • lineNumber: บรรทัดที่ทำให้เกิดข้อผิดพลาดขึ้น
  • columnNumber: คอลัมน์ในบรรทัดที่ทำให้เกิดข้อผิดพลาดขึ้น
  • stack: ลำดับสแต็กการทำงานของฟังก์ชันเมื่อเกิดข้อผิดพลาดขึ้น

นี่เป็น Property ที่เราสามารถเข้าถึงได้จากออบเจ็คของข้อผิดพลาดที่เกิดขึ้นในภาษา JavaScript ยกตัวอย่างเช่น

try {
    foo
} catch (error) {
    // Standrd property
    console.log("Error name: " + error.name);
    console.log("Error message: " + error.message);
    console.log("toString: " + error.toString());

    // Non Standrd property
    console.log(error.fileName);
    console.log(error.lineNumber);
    console.log(error.columnNumber);
    console.log(error.stack);
}

นี่เป็นผลลัพธ์ในการทำงานของโปรแกรม

Error name: ReferenceError
Error message: foo is not defined
toString: ReferenceError: foo is not defined
undefined
undefined
undefined
ReferenceError: foo is not defined
    at Object.<anonymous> (C:\marcuscode\javascript\exceptions\error.js:2:5)
    at Module._compile (internal/modules/cjs/loader.js:1256:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1277:10)
    at Module.load (internal/modules/cjs/loader.js:1105:32)
    at Function.Module._load (internal/modules/cjs/loader.js:967:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

นี่เป็นการแสดงรายละเอียดเกี่ยวกับข้อผิดพลาดที่เกิดขึ้น สังเกตว่าคุณจะเห็นค่าจากบาง Property ที่เป็น undefinded เช่น fileName, lineNumber หรือ columnNumber นั่นเป็นเพราะว่า Property เหล่านี้ไม่สนับสนุนโดย Node.js แต่มันอาจสนับสนุนโดยสภาพแวดล้อมการทำงานอื่นๆ เช่น เว็บบราวน์เซอร์

และนี่เป็นรายการของคลาสข้อผิดพลาดมาตรฐานทั้งหมดในภาษา JavaScript ในการทำงานที่ผิดพลาดต่างๆ คลาสเหล่านี้สืบทอดมาจากคลาส Error เราสามารถสร้างคลาสโดยสืบทอดจากคลาสเหล่านี้ หรือนำมาสร้างออบเจ็คเพื่อ throw ข้อผิดพลาดได้

  • EvalError: ข้อผิดพลาดเกี่ยวกับการอ่านโค้ดที่ไม่ถูกต้องของภาษา JavaScript ด้วยฟังก์ชัน eval
  • RangeError: ข้อผิดพลาดเกี่ยวกับช่วงของข้อมูลไม่ถูกต้อง
  • ReferenceError: ข้อผิดพลาดเมื่อใช้งานชื่อของตัวแปรหรือฟังก์ชันที่ไม่ได้ถูกประกาศเอาไว้
  • SyntaxError: ข้อผิดพลาดเกี่ยวกับโครงสร้างของโปรแกรมไม่ถูกต้อง
  • TypeError: ข้อผิดพลาดเกี่ยวกับการใช้ข้อมูลผิดประเภท
  • URIError: ข้อผิดพลาดเกี่ยวกับ URL ไม่ถูกต้องเมือแปลง URL ด้วยฟังก์ชัน encodeURI หรือ decodeURI

ซึ่งคลาสเหล่านี้เป็นคลาสที่สืบทอดมาจากคลาส Error และมันมี Property ที่เราได้อธิบายไปแล้วก่อนหน้า และเราสามารถใช้มันในการสร้างออบเจ็คของข้อผิดพลาด นี่เป็นตัวอย่างของการทำให้เกิดข้อผิดพลาดมาตฐานในภาษา JavaScript

noFunction();
// Output: ReferenceError: noFunction is not defined

เมื่อเรารันโค้ดนี้ ข้อผิดพลาด ReferenceError จะถูก throw อัตโนมัติโดยตัวแปรของภาษาหรือ JavaScript engine อย่างไรก็ตาม เราสามารถใช้คลาสเหล่านี้เพื่อสร้างออบเจ็คของข้อผิดพลาดและ throw ด้วยตัวเองได้ ยกตัวอย่างเช่น

let value = 20;
if (value < 0 || value > 10) {
    throw new RangeError("Invalid value only 1 - 10 allowed.");
}
// Output: RangeError: Invalid value only 1 - 10 allowed.

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

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับ Exception และ Error ในภาษา JavaScript เราได้พูดถึงการจัดการข้อผิดพลาดด้วยคำสั่ง try catch และ finally การสร้างคลาสของข้อผิดพลาดที่สืบทอดจากคลาส Error และเรียนรู้เกี่ยวกับคลาส Error มาตฐานของภาษา ซึ่งเป็นวิธีที่จะรับมือกับข้อผิดพลาดที่อาจเกิดขึ้นในโปรแกรมของเราและจัดการกับมันอย่างถูกต้อง