memeriksa kesalahan typeof di JS

153

Dalam JS sepertinya tidak mungkin untuk memeriksa apakah argumen yang dilewatkan ke suatu fungsi sebenarnya dari jenis 'kesalahan' atau contoh dari Kesalahan.

Misalnya, ini tidak valid:

typeof err === 'error'

karena hanya ada 6 jenis yang mungkin (dalam bentuk string):

Typeof operator mengembalikan informasi tipe sebagai string. Ada enam kemungkinan nilai yang typeofmengembalikan:

"number", "string", "boolean", "object", "function" dan "undefined".

MSDN

Tetapi bagaimana jika saya memiliki use case sederhana seperti ini:

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);
    }
}

jadi apa cara terbaik untuk menentukan apakah argumen adalah turunan dari Kesalahan?

adalah instanceofoperator bantuan?

Alexander Mills
sumber
10
Ya, gunakanerr instanceof Error
colecmc
2
@ colecmc bukankah itu akan bermasalah jika kesalahan mungkin berasal dari kode dalam bingkai atau jendela lain? Dalam hal ini akan ada objek Kesalahan prototipe yang berbeda, dan instanceof tidak akan berfungsi seperti yang diharapkan. (lihat developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Doin
@Gabung, saya kira tidak. Itu hanya akan memvalidasi objek kesalahan yang sebenarnya.
colecmc
1
@ colecmc, saya pikir Anda akan menemukan bahwa jika Anda telah errmemasukkan (katakanlah) iframe, tetapi kemudian meneruskannya ke jendela induk untuk diserahkan, Anda akan mendapatkannya (err instanceof Error) === false. Itu karena iframe dan jendela induknya memiliki Errorprototipe objek yang berbeda . Demikian pula objek seperti obj = {};kehendak, ketika diteruskan ke fungsi yang berjalan di jendela yang berbeda, yeild (obj instanceof Object)===false. (Bahkan yang terburuk, di IE, jika Anda menyimpan referensi ke obj setelah jendelanya dihancurkan atau dinavigasi, mencoba memanggil prototipe objek fns seperti obj.hasOwnProperty()akan melempar kesalahan!)
Doin
bagaimana Anda memeriksa jenis kesalahan tho? yaitu catch((err)=>{if (err === ENOENT)mengembalikan ENOENT is not definedkesalahan?
oldboy

Jawaban:

261

Anda dapat menggunakan instanceofoperator (tetapi lihat peringatan di bawah!).

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

Di atas tidak akan berfungsi jika kesalahan dilemparkan ke jendela / bingkai / iframe yang berbeda dari tempat pemeriksaan terjadi. Dalam hal ini, instanceof Errorcek akan mengembalikan false, bahkan untuk suatu Errorobjek. Dalam hal itu, pendekatan termudah adalah mengetik-bebek.

if (myError && myError.stack && myError.message) {
  // it's an error, probably
}

Namun, pengetikan bebek dapat menghasilkan false positive jika Anda memiliki objek non-error yang berisi stackdan messageproperti.

Trott
sumber
1
@ AurélienRibon Ini berfungsi dengan baik dengan sebuah ReferenceErrorinstance. Anda sedang memeriksa ReferenceErrorobjek global . Coba ini:try { foo } catch (e) { console.log(e instanceof Error) } Log true. Jika Anda mencoba memeriksa ReferenceErrorobjek global karena beberapa alasan, Anda dapat menggunakanError.isPrototypeOf(ReferenceError)
Trott
1
@ AurélienRibon (Eh, juga, ya, tidak yakin apakah Anda mengatakan "Ini tidak akan berfungsi dengan ReferenceError" yang tidak benar, atau jika Anda hanya menunjukkan "Ini tidak akan berfungsi dengan objek ReferenceError global" yang benar-benar benar, walaupun saya mengalami kesulitan untuk datang dengan situasi di mana seseorang akan memeriksa itu, tapi itu mungkin mengatakan lebih banyak tentang kurangnya imajinasi saya daripada validitas use case).
Trott
Haha, maaf soal itu kawan-kawan, aku baru saja terkunci ke dalam kesalahan aneh dimana semua milikku ReferenceError contoh bukan contoh Error. Ini karena panggilan ke vm.runInNewContext()dalam simpul, di mana semua prototipe standar didefinisikan ulang. Semua hasil saya bukan contoh objek standar. Saya mencari di SO tentang hal ini, dan jatuh ke utas ini :)
Aurelien Ribon
1
Anda dapat mencobaconst error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
Aamir Afridi
bagaimana Anda memeriksa apakah itu instanceofjenis kesalahan khusus tho?
oldboy
25

Saya menanyakan pertanyaan asli - Jawaban @ Trott pasti yang terbaik.

Namun dengan JS sebagai bahasa yang dinamis dan dengan begitu banyak lingkungan runtime JS, instanceofoperator dapat gagal terutama dalam pengembangan front-end ketika melintasi batas seperti iframe. Lihat: https://github.com/mrdoob/three.js/issues/5886

Jika Anda baik-baik saja dengan mengetik bebek, ini seharusnya bagus:

let isError = function(e){
 return e && e.stack && e.message;
}

Saya pribadi lebih suka bahasa yang diketik secara statis, tetapi jika Anda menggunakan bahasa yang dinamis, lebih baik merangkul bahasa yang dinamis dengan bahasa aslinya, daripada memaksanya berperilaku seperti bahasa yang diketik secara statis.

jika Anda ingin mendapatkan sedikit lebih tepat, Anda bisa melakukan ini:

   let isError = function(e){
     return e && e.stack && e.message && typeof e.stack === 'string' 
            && typeof e.message === 'string';
    }
Alexander Mills
sumber
3
Saya lebih suka versi ini saat menulis fungsi utilitas atau perpustakaan. Itu tidak membatasi pengguna untuk satu konteks global tertentu dan juga menangani dengan benar kesalahan terurai dari JSON.
terkekeh
terima kasih, ya dalam banyak kasus, jika terlihat seperti kesalahan, kita dapat memperlakukannya sebagai kesalahan. dalam beberapa kasus mengetik bebek benar-benar dapat diterima, dalam beberapa kasus itu tidak dapat diterima sama sekali, dalam hal ini, baik-baik saja.
Alexander Mills
Saya melakukan beberapa debugging menggunakan debugger, dan tumpukan dan pesan benar-benar tampak sebagai satu-satunya dua properti non-asli pada instance Error.
Alexander Mills
1
@ Trott Anda mungkin tertarik untuk mengetahui tentang instanceofkegagalan operator dalam beberapa kasus, lihat artikel yang ditautkan.
Alexander Mills
1
Ini sebenarnya yang paling sederhana sehingga bekerja dengan berbagai jenis kesalahan (yaitu Error, ReferenceError, ...). Dan di lingkungan saya, instanceofgagal total dalam banyak keadaan.
Alexis Wilke
10
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

Satu-satunya masalah dengan ini

myError instanceof Object // true

Alternatif untuk ini adalah dengan menggunakan properti konstruktor.

myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true

Meskipun perlu dicatat bahwa kecocokan ini sangat spesifik, misalnya:

myError.constructor === TypeError // false
Tom
sumber
2

Anda dapat menggunakan Object.prototype.toStringuntuk dengan mudah memeriksa apakah suatu objek adalah Error, yang akan bekerja untuk bingkai yang berbeda juga.

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([]));

hev1
sumber
1

Anda dapat menggunakan obj.constructor.name untuk memeriksa "kelas" suatu objek https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

Sebagai contoh

var error = new Error("ValidationError");
console.log(error.constructor.name);

Baris di atas akan mencatat "Kesalahan" yang merupakan nama kelas objek. Ini dapat digunakan dengan kelas apa pun di javascript, jika kelas tersebut tidak menggunakan properti yang menggunakan nama "nama"

persistent_poltergeist
sumber
Ini tidak dapat diandalkan ketika mengecilkan kode dan menggunakan subclass kesalahan
felixfbecker
1

Terima kasih @ Trott untuk kode Anda, saya hanya menggunakan kode yang sama dan ditambahkan dengan contoh kerja waktu nyata untuk kepentingan orang lain.

<html>
<body >

<p>The **instanceof** operator returns true if the specified object is an instance of the specified object.</p>



<script>
	var myError = new Error("TypeError: Cannot set property 'innerHTML' of null"); // error type when element is not defined
	myError instanceof Error // true
	
	
	
	
	function test(){
	
	var v1 = document.getElementById("myid").innerHTML ="zunu"; // to change with this
	
	try {
		  var v1 = document.getElementById("myidd").innerHTML ="zunu"; // exception caught
		  } 
		  
	catch (e) {
		  if (e instanceof Error) {
			console.error(e.name + ': ' + e.message) // error will be displayed at browser console
		  }
  }
  finally{
		var v1 = document.getElementById("myid").innerHTML ="Text Changed to Zunu"; // finally innerHTML changed to this.
	}
	
	}
	
</script>
<p id="myid">This text will change</p>
<input type="button" onclick="test();">
</body>
</html>

Zabi Baig
sumber
0

Atau gunakan ini untuk berbagai jenis kesalahan

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
Chris
sumber