проверка на ошибку typeof в JS


154

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

так каков наилучший способ определить, является ли аргумент экземпляром Error?

является instanceofоператором какой - либо помощи?


10
Да, использоватьerr instanceof Error
— colecmc

2
@colecmc не будет ли это проблематично, если ошибка может быть из-за кода во фрейме или в другом окне? В этом случае будут разные прототипы объектов Error, и instanceof не будет работать должным образом. (см developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... )
— Играешь

@ Делай, я так не думаю. Это просто подтвердит фактический объект ошибки.
— colecmc

1
@colecmc, я думаю, вы обнаружите, что если вы добавили err(скажем) iframe, но затем передаете его родительскому окну для передачи, вы получите (err instanceof Error) === false. Это связано с тем, что у iframe и его родительского окна разные Errorпрототипы объектов. Точно так же объект, как obj = {};will, при передаче функции, выполняющейся в другом окне, yeild (obj instanceof Object)===false. (Что еще хуже, в IE, если вы сохраните ссылку на obj после того, как окно будет разрушено или перемещено, попытка вызвать прототип объекта fns like obj.hasOwnProperty()вызовет ошибки!)
— Doin

как вы проверяете тип ошибки, хотя? т.е. catch((err)=>{if (err === ENOENT)возвращает ENOENT is not definedошибку?
— старик

Ответы:


262

Вы можете использовать instanceofоператор (но см. Предостережение ниже!).

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

Вышеуказанное не сработает, если ошибка была выдана в другом окне / фрейме / фрейме, отличном от того, где происходит проверка. В этом случае instanceof Errorпроверка вернет false, даже для Errorобъекта. В таком случае, самый простой подход - это печатание на клавиатуре.

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

Тем не менее, типизация утки может привести к ложным срабатываниям, если у вас есть объекты без ошибок, которые содержат stackи messageсвойства.


1
@ AurélienRibon Отлично работает с ReferenceErrorэкземпляром. Вы проверяете глобальный ReferenceErrorобъект. Попробуйте это: try { foo } catch (e) { console.log(e instanceof Error) }это логи true. Если ReferenceErrorпо какой-то причине вы пытаетесь проверить глобальный объект, вы можете использоватьError.isPrototypeOf(ReferenceError)
— Trott

1
@ AurélienRibon (Ух, да, да, не был уверен, что вы говорите «Это не будет работать с ReferenceError», что неверно, или если вы просто указали «Это не будет работать с глобальным объектом ReferenceError») это абсолютно правильно, хотя мне трудно придумать ситуацию, в которой можно было бы проверить это, но это может сказать больше о моей нехватке воображения, чем обоснованность варианта использования).
— Тротт

Ха-ха, извините за этих парней, я просто запутался в странной ошибке, где все мои ReferenceErrorэкземпляры не были экземплярами Error. Это произошло из-за вызова vm.runInNewContext()в узле, где все стандартные прототипы переопределяются. Все мои результаты не были экземплярами стандартных объектов. Я искал в SO об этом и попал в эту ветку :)
— Aurelien Ribon

1
Вы можете попробоватьconst error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
— Аамир Африди

Как вы проверите, если instanceofэто определенный тип ошибки, хотя?
— старик

25

Я задал оригинальный вопрос - ответ @ Тротта, безусловно, лучший.

Однако, поскольку JS является динамическим языком, а среда выполнения JS так много, instanceofоператор может потерпеть неудачу, особенно при разработке интерфейса, при пересечении границ, таких как iframes. Смотрите: https://github.com/mrdoob/three.js/issues/5886

Если вы в порядке с печатанием утки, это должно быть хорошо:

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

Я лично предпочитаю статически типизированные языки, но если вы используете динамический язык, лучше использовать динамический язык таким, какой он есть, а не заставлять его вести себя как статически типизированный язык.

если вы хотите получить более точную информацию, вы можете сделать это:

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

3
Я предпочитаю эту версию при написании служебной функции или библиотеки. Он не ограничивает пользователей одним конкретным глобальным контекстом, а также правильно обрабатывает десериализованные ошибки из JSON.
— хихикать

спасибо, да во многих случаях, если это выглядит как ошибка, мы можем рассматривать как ошибку. в некоторых случаях типирование утки является полностью приемлемым, в некоторых случаях это вообще неприемлемо, в этом случае, совершенно нормально.
— Александр Миллс

Я выполнил некоторую отладку с использованием отладчика, и стек и сообщение действительно являются единственными двумя несобственными свойствами в экземплярах Error.
— Александр Миллс

1
@Trott, вам может быть интересно узнать о сбое instanceofоператора в некоторых случаях, см. Статью по ссылке .
— Александр Миллс

1
Это на самом деле самый простой , так что работает с различными типами ошибок (то есть Error, ReferenceError...). И в моем окружении instanceofнеудачи с треском проваливаются при многих обстоятельствах.
— Алексис Вилке

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

Единственная проблема с этим

myError instanceof Object // true

Альтернативой этому было бы использование свойства конструктора.

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

2

Вы можете 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([]));


1

Вы можете использовать obj.constructor.name для проверки «класса» объекта https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

Например

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

В приведенной выше строке будет записано «Ошибка», которая является именем класса объекта. Это может быть использовано с любыми классами в javascript, если класс не использует свойство, которое называется «имя»


Это ненадежно при минимизации кода и использовании подклассов ошибок
— felixfbecker

1

Спасибо @Trott за ваш код, я просто использовал тот же код и добавил рабочий пример в реальном времени для пользы других.

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


0

Или используйте это для различных типов ошибок

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.