JS'de typeof hatasını kontrol etme


172

JS'de, bir işleve iletilen bir bağımsız değişkenin aslında "hata" türünde mi yoksa bir Hata örneği mi olduğunu kontrol etmek mümkün görünmemektedir.

Örneğin, bu geçerli değildir:

typeof err === 'error'

yalnızca 6 olası tür olduğundan (dizeler biçiminde):

Typeof operatörü tür bilgilerini bir dizge olarak döndürür. Dönen altı olası değer vardır typeof:

"sayı", "dize", "mantıksal", "nesne", "işlev" ve "tanımsız".

MSDN

Ama ya bunun gibi basit bir kullanım durumum varsa:

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

öyleyse, bir argümanın Hata örneği olup olmadığını belirlemenin en iyi yolu nedir?

olan instanceofherhangi bir yardım operatörü?


16
Evet, kullanınerr instanceof Error
colecmc

2
@colecmc, hata bir çerçevedeki veya başka bir penceredeki koddan gelmişse bu sorunlu olmaz mı? Bu durumda, farklı prototip Error nesneleri olacaktır ve instanceof beklendiği gibi çalışmayacaktır. ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… bakın )
Doin

@Doin, sanmıyorum. Sadece gerçek hata nesnesini doğrulayacaktır.
colecmc

1
@colecmc, sanırım errbir iframe attıysanız (diyelim), ancak sonra onu teslim etmek için ana pencereye geçirdiyseniz, alacağınızı göreceksiniz (err instanceof Error) === false. Bunun nedeni, iframe'in ve üst penceresinin farklı, farklı Errornesne prototiplerine sahip olmasıdır. Benzer şekilde obj = {};will gibi bir nesne , farklı bir pencerede çalışan bir işleve geçirildiğinde yeild (obj instanceof Object)===false. (En kötüsü, IE'de, penceresi yok edildikten veya gezindikten sonra obj için bir referans tutarsanız, fns gibi nesne prototipini çağırmaya çalışmak obj.hasOwnProperty()hatalara neden olur!)
Doin

hata türünü nasıl kontrol edersiniz? yani hata mı catch((err)=>{if (err === ENOENT)döndürüyor ENOENT is not defined?
yaşlı çocuk

Yanıtlar:


286

instanceofOperatörü kullanabilirsiniz (ancak aşağıdaki uyarıya bakın!).

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

Hata, kontrolün gerçekleştiği yerden farklı bir pencere / çerçeve / iframe'e atılmışsa, yukarıdakiler çalışmayacaktır. Bu durumda instanceof Errorkontrol, bir Errornesne için bile yanlış döndürür . Bu durumda, en kolay yaklaşım ördek yazmadır.

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

Bununla birlikte, ördek yazma, içeren stackve messageözelliklerinde hata olmayan nesneleriniz varsa yanlış pozitifler üretebilir .


1
@ AurélienRibon Bir ReferenceErrorörnekle gayet iyi çalışıyor . Global ReferenceErrornesneyi kontrol ediyorsunuz . Şunu deneyin: try { foo } catch (e) { console.log(e instanceof Error) }Günlükleri kaydeder true. Herhangi bir ReferenceErrornedenle global nesneyi kontrol etmeye çalışıyorsanız , şunu kullanabilirsinizError.isPrototypeOf(ReferenceError)
Trott

1
@ AurélienRibon (Uh, evet, yanlış olan "Bu bir ReferenceError ile çalışmaz" mı diyorsunuz, yoksa sadece "Bu global ReferenceError nesnesiyle çalışmaz" mı diyorsunuz emin değilim Bu kesinlikle doğru, ancak birinin bunu kontrol edeceği bir durumla karşılaşmakta zorlanmama rağmen, bu, kullanım durumunun geçerliliğinden çok hayal gücümün eksikliğiyle ilgili daha fazla şey söyleyebilir).
Trott

Haha, o çocuklar için üzgünüm, tüm ReferenceErrorörneklerimin örnekleri olmadığı garip bir hataya kilitlendim Error. Bu, vm.runInNewContext()tüm standart prototiplerin yeniden tanımlandığı bir düğüm içi çağrısından kaynaklanıyordu . Tüm sonuçlarım standart nesnelerin örnekleri değildi. SO'ya bakıyordum ve bu konuya düştüm :)
Aurelien Ribon

1
Deneyebilirsinizconst error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
Aamir Afridi

bunun instanceofbelirli bir hata türü olup olmadığını nasıl kontrol edersiniz ?
oldboy

28

Orijinal soruyu sordum - @ Trott'un cevabı kesinlikle en iyisi.

Bununla birlikte, JS'nin dinamik bir dil olması ve çok sayıda JS çalışma zamanı ortamının olmasıyla, instanceofoperatör özellikle iframe'ler gibi sınırları aşarken ön uç geliştirmede başarısız olabilir. Bakınız: https://github.com/mrdoob/three.js/issues/5886

Ördek yazmada sorun yoksa, bu iyi olabilir:

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

Ben şahsen statik olarak yazılmış dilleri tercih ederim, ancak dinamik bir dil kullanıyorsanız, onu statik olarak yazılmış bir dil gibi davranmaya zorlamak yerine dinamik bir dili kucaklamak en iyisidir.

biraz daha kesin olmak istersen, bunu yapabilirsin:

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

3
Bir yardımcı program işlevi veya kitaplık yazarken bu sürümü tercih ederim. Kullanıcıları belirli bir genel bağlamla sınırlamaz ve ayrıca JSON'dan gelen serileştirilmemiş hataları düzgün bir şekilde işler.
snickle

teşekkürler, evet, çoğu durumda, bir hata gibi görünüyorsa, bir hata gibi davranabiliriz. bazı durumlarda ördek yazımı tamamen kabul edilebilir, bazı durumlarda hiç kabul edilemez, bu durumda gayet iyi.
Alexander Mills

Bir hata ayıklayıcı kullanarak bazı hata ayıklama yaptım ve hata örneklerinde yığın ve ileti gerçekten yerel olmayan yalnızca iki özellik olarak görünüyor.
Alexander Mills

1
@Trott instanceofbazı durumlarda operatörün arızalanması hakkında bilgi almak isteyebilirsiniz , bağlantılı makaleye bakın.
Alexander Mills

1
Bu hataların farklı türleri ile çalışır, böylece aslında basit olanı (yani Error, ReferenceError, ...). Ve benim çevremde, instanceofbirçok durumda sefil bir şekilde başarısız oluyor.
Alexis Wilke

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

Bununla ilgili tek sorun

myError instanceof Object // true

Bunun bir alternatifi, yapıcı özelliğini kullanmak olabilir.

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

Bu eşleşmenin çok spesifik olduğu unutulmamalıdır, örneğin:

myError.constructor === TypeError // false

2

Farklı çerçeveler için de çalışacak Object.prototype.toStringbir nesnenin bir nesne olup olmadığını kolayca kontrol etmek için kullanabilirsiniz 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([]));


Bunu sevdiğimden emin değilim. Bir hatanın dizildiği zaman tam olarak bu biçimde olması gerektiğini söyleyen herhangi bir standart var mı bilmiyorum. Bunun uygulamaya bağlı olacağını düşünürdüm ...
Aaron

1

Bir nesnenin "sınıfını" kontrol etmek için obj.constructor.name kullanabilirsiniz https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

Örneğin

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

Yukarıdaki satır, nesnenin sınıf adı olan "Hata" yı kaydedecektir. Bu, sınıf "name" adıyla anılan bir özellik kullanmıyorsa, javascript'teki herhangi bir sınıfla kullanılabilir.


Bu, kodu
küçültürken

1

Kodunuz için teşekkürler @Trott, sadece aynı kodu kullandım ve başkalarının yararına gerçek zamanlı bir çalışma örneği ekledim.

<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>


Hey, 2020 - Lütfen SO yayınlarında var kullanmayın
refaelio

0

Veya bunu farklı hata türleri için kullanın

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.