javascript - การตรวจสอบ typeof error ใน JS
ใน JS ดูเหมือนว่าจะไม่สามารถตรวจสอบได้ว่าอาร์กิวเมนต์ที่ส่งไปยังฟังก์ชันนั้นเป็นประเภท 'error' จริงหรือเป็นอินสแตนซ์ของ Error หรือไม่
ตัวอย่างเช่น นี่ไม่ถูกต้อง:
typeof err === 'error'เนื่องจากมีเพียง 6 ประเภทที่เป็นไปได้ (ในรูปแบบของสตริง):
ตัวดำเนินการ typeof จะคืนข้อมูลประเภทในรูปแบบสตริง มีค่าเป็นไปได้หกค่าที่ typeof คืนค่า:
"ตัวเลข", "สตริง", "บูลีน", "ออบเจ็กต์", "ฟังก์ชัน" และ "ไม่กำหนด".
MSDN
แต่ถ้าฉันมีกรณีการใช้งานง่ายๆ แบบนี้ล่ะ:
function errorHandler(err) {
if (typeof err === 'error') {
throw err;
}
else {
console.error('Unexpectedly, no error was passed to error handler. But here is the message:',err);
}
}
แล้ววิธีที่ดีที่สุดในการกำหนดว่าข้อโต้แย้งเป็นตัวอย่างของข้อผิดพลาดคืออะไร?
ตัวดำเนินการ instanceof มีประโยชน์อะไรไหม?
คำตอบ #1
คุณสามารถใช้ตัวดำเนินการ instanceof ได้ (แต่ดูข้อควรระวังด้านล่าง!)
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false
วิธีข้างต้นจะใช้ไม่ได้ถ้าข้อผิดพลาดเกิดขึ้นในหน้าต่าง/กรอบ/iframe ที่แตกต่างจากที่มีการตรวจสอบ ในกรณีนั้น การตรวจสอบ instanceof Error จะคืนค่าเป็น false แม้กระทั่งสำหรับอ็อบเจ็กต์ Error ในกรณีนั้น วิธีที่ง่ายที่สุดคือการใช้ duck-typing
if (myError && myError.stack && myError.message) {
// it's an error, probably
}
อย่างไรก็ตาม การใช้ duck-typing อาจทำให้เกิดผลบวกเทียมได้หากคุณมีวัตถุที่ไม่ใช่ข้อผิดพลาดแต่มีคุณสมบัติ stack และ message
คำตอบ #2
ฉันถามคำถามเดิม - คำตอบของ @Trott แน่นอนว่าเป็นคำตอบที่ดีที่สุด
อย่างไรก็ตาม ด้วย JS เป็นภาษาที่มีความยืดหยุ่นและมีสภาพแวดล้อมการรัน JS จำนวนมาก ตัวดำเนินการ instanceof อาจล้มเหลวโดยเฉพาะในการพัฒนาแบบ front-end เมื่อข้ามเขตแดนเช่น iframes ดูที่: https://github.com/mrdoob/three.js/issues/5886
ถ้าคุณโอเคกับ duck typing แบบนั้น ก็น่าจะใช้ได้:
let isError = function(e){
return e && e.stack && e.message;
};
ฉันส่วนตัวชอบภาษาที่มีการกำหนดชนิดตัวแปรแบบคงที่ แต่ถ้าคุณกำลังใช้ภาษาที่มีการกำหนดชนิดตัวแปรแบบไดนามิก ควรยอมรับภาษานั้นในแบบที่มันเป็น มากกว่าพยายามบังคับให้มันทำงานเหมือนภาษาที่มีการกำหนดชนิดตัวแปรแบบคงที่
ถ้าคุณต้องการให้แม่นยำขึ้นอีกนิด คุณสามารถทำแบบนี้ได้:
let isError = (e) => {
return e &&
e.stack &&
e.message &&
typeof e.stack === 'string' &&
typeof e.message === 'string';
};
คำตอบ #3
คุณสามารถใช้ Object.prototype.toString เพื่อตรวจสอบได้อย่างง่ายดายว่าตัวแปรเป็น Error หรือไม่ ซึ่งจะสามารถใช้งานได้กับเฟรมต่าง ๆ ด้วย
function isError(obj){
return Object.prototype.toString.call(obj) === "[object Error]";
}
function isError(obj){
return Object.prototype.toString.call(obj) === "[object Error]";
}
console.log("Error:", isError(new Error));
console.log("RangeError:", isError(new RangeError));
console.log("SyntaxError:", isError(new SyntaxError));
console.log("Object:", isError({}));
console.log("Array:", isError([]));พฤติกรรมนี้ได้รับการรับประกันโดยข้อกำหนดของภาษา ECMAScript
Object.prototype.toString:
เมื่อมีการเรียกใช้เมธอด toString ขั้นตอนดังต่อไปนี้จะถูกดำเนินการ:
- ถ้าค่าตัวนี้ไม่ถูกกำหนด ให้คืนค่า "[object Undefined]".
- ถ้าค่าตัวนี้เป็นค่าว่าง ให้คืนค่า "[object Null]".
- ให้ O เป็นผลลัพธ์ของการเรียกใช้ ToObject โดยส่งค่า this เป็นอาร์กิวเมนต์
- ให้ class เป็นค่าของสมบัติภายใน [[Class]] ของ O
- ส่งค่าของสตริงที่ได้มาจากการรวมสตริงทั้งสาม "[object ", class, และ "]"
คุณสมบัติของตัวอย่างข้อผิดพลาด:
อินสแตนซ์ของ Error สืบทอดคุณสมบัติจากอ็อบเจ็กต์ต้นแบบของ Error และค่าคุณสมบัติภายใน
[[Class]]ของพวกมันคือ "Error" อินสแตนซ์ของ Error ไม่มีคุณสมบัติพิเศษใด ๆ
คำตอบ #4
โซลูชัน TypeScript
คุณสามารถกำหนดตัวป้องกันประเภทที่ผู้ใช้กำหนดเองได้ เพียงแค่ต้องกำหนดฟังก์ชันที่ชนิดการคืนค่าของมันเป็นตัวทำนายประเภท
คุณสามารถตรวจสอบได้ว่าตัวแปรเป็นข้อผิดพลาดแบบนี้
const isError = (err: unknown): err is Error => err instanceof Error;
แล้วภายใน try catch ให้ตรวจสอบว่ามีลักษณะเช่นนี้
try {
login(username, password);
} catch (err) {
if (isError(err)) {
console.log(err.message);
}
คำตอบ #5
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false
ปัญหาเดียวกับเรื่องนี้คือ
myError instanceof Object // true
ทางเลือกหนึ่งสำหรับสิ่งนี้คือการใช้คุณสมบัติ constructor
myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true
แม้ว่าควรสังเกตว่าการจับคู่นี้เฉพาะมาก ตัวอย่างเช่น:
myError.constructor === TypeError // false
