2012-01-29 11 views
29

Jakoś to nie ma ochoty kulminacji 50 lat programowania rozwoju język:Odpowiednie zakaz Łańcuch JavaScript wyjątki

throw "My exception message here"; 

Co to jest poprawny sposób to zrobić wyjątki w JavaScript, tak że

  • Można je zidentyfikować (instanceof)

  • Mogą przenosić inne ładunki oprócz domyślnego komunikatu i śledzenia stosu

  • Oni „podklasy” baza Wyjątek, tak że konsola debugowania i takie można wyciągnąć sensowne informacje o wyjątku

  • możliwymi wyjątkami zagnieżdżonych (konwersja wyjątek do drugiego): jeśli trzeba złapać wyjątek i przekaż nowy jeden orignal ślad stosu zostanie zachowana i może być sensownie odczytać za pomocą narzędzi debugowania

  • Podążają Javascript najlepszych praktyk

+0

JavaScript naprawdę ich nie ma? Czy można serializować dowolny obiekt do napisu w JS? –

+2

@ VladislavZorov: Tak, JavaScript ma te. –

+0

Wyjaśniono potrzebę zagnieżdżonych wyjątków –

Odpowiedz

25

throw new Error("message");

lub jeśli chcesz być bardziej szczegółowe zastosowanie jedna z Error Objects

Ważne jest, aby upewnić się, rzucać prawdziwe błędy, ponieważ zawierają one ślad stosu. Rzucanie łańcuchem jest głupie, ponieważ nie ma do niego dołączonych żadnych metadanych.

Można również Podklasa błędy

// for some sensible implementation of extend 
// https://gist.github.com/1441105#file_1pd.js 
var MyError = extend(Object.create(Error.prototype), { 
    ... 
}); 
+0

"dla jakiejś rozsądnej implementacji przedłużenia" co? Nie rozumiem tego. –

+3

Wzorzec obiektu Javascript extend jest powszechnym wzorcem projektowym zaimplementowanym w wielu frameworkach JavaScript, np. jQuery http://api.jquery.com/jQuery.extend/ –

+0

@Mikko: Tak, wiem, ale nie dostaję tego zdania. Czy czegoś nie brakuje? –

9

baza „wyjątek” w JavaScript jest Bui LT-in Error obiektu:

throw new Error("My exception message here"); 

Można zdefiniować niestandardowe wyjątki jak:

function CustomError(message) { 
    this.message = message; 
} 

CustomError.prototype = new Error(); 
CustomError.prototype.constructor = CustomError; 

Sprawdzenie typu wyjątku z instanceof. Istnieje również handy list of built-in exceptions.

+5

Unikaj wywoływania 'nowego błędu' w twoim przypisaniu' CustomError', ponieważ wywołuje on konstruktor w 'CustomError' pozostawiając za sobą dane śledzenia stosu. Zamiast tego korzystaj z prototypowego rozszerzenia ('CustomError.prototype = Object.create (Error);') – Raynos

+0

@Raynos Dlaczego używasz Object.create (Error) zamiast nowego Error? Czy możesz wyjaśnić różnicę między tymi dwoma? – radicalmatt

2

Możesz utworzyć obiekt Error, dzwoniąc pod numer Error constructor. Obiekt error może mieć wiadomość i imię. Podczas przechwytywania możesz sprawdzić konkretną nazwę lub możesz utworzyć niestandardowy typ błędu, dziedzicząc prototyp Error. Pozwala to na użycie instanceof w celu rozróżnienia różnych typów błędów.

// Create a new object, that prototypally inherits from the Error constructor. 
function MyError(message) { 
    this.message = message || "Default Message"; 
} 
MyError.prototype = new Error(); 
MyError.prototype.constructor = MyError; 

try { 
    throw new MyError(); 
} catch (e) { 
    console.log(e.name);  // "MyError" 
    console.log(e.message); // "Default Message" 
} 

try { 
    throw new MyError("custom message"); 
} catch (e) { 
    console.log(e.name);  // "MyError" 
    console.log(e.message); // "custom message" 
} 

Przykład wzięty z: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error

+2

Unikaj 'x.prototype = new y();' favor 'x.prototype = Object.create (y.prototype)' – Raynos

+0

@Raynos W środowisku przeglądarki 'Object.create' może nie być dostępny i potrzebujesz polyfill. W środowisku JavaScript> = 1.8.5 zgadzam się. – Eliasdx

+1

jest jeszcze lepiej polyfill Object.create następnie użyć 'new y();' – Raynos

3

Nie można tego zrobić, i spełniają wymagania pytanie.

Dlaczego?

Problem polega na uzyskaniu stosu. Macierzysty obiekt błędu (NativeError od teraz), inicjuje stos, gdy wywoływany jest jego konstruktor.Aby uzyskać stos w MyError (twojej podklasie błędów), musisz wywołać NativeConstructor w konstruktorze MyError. Tak więc klasa MyError wygląda mniej więcej tak:

function MyError(msg) { 
    Error.call(this, msg); 
} 

Ale to nie działa. Ponieważ zgodnie z HTML5 spec:

"jeśli wywołasz Error jako funkcję, zwraca nowy obiekt Error".

Zamiast konstruktora błędu i inicjowania niestandardowej klasy błędów, tworzy obiekt błędu, którego nie potrzebujesz. Nie znalazłem sposobu na wywołanie konstruktora NativeError i zainicjowałem podklasę MyError.

Nie wszystko jest stracone.

Jeśli rozwiążemy pierwotne wymagania dotyczące pytań i zapomnimy o "instanceof", aby przetestować klasę wyjątku (tak i tak w Javie), i zamiast tego użyj "name", można to zrobić. Po prostu zadeklaruj MyError jako:

function MyError(msg, customArg) { 
    var e = new Error(msg); 
    e.name = "MyError"; 
    e.custom = customArg; 
    return e; 
} 

Oto, co robię. Zamiast włączania "instanceof", zamiast tego włącz "name".

+0

Nie wszystkie biblioteki respektują zmienną 'name'. [Bluebird] (http://bluebirdjs.com/docs/api/catch.html) na przykład wymaga niestandardowego "prototypu" błędu, aby zejść z 'Error.prototype'. W rzeczywistości zależnie od stanu obiektu może napotkać cię kłopoty, jeśli nie jesteś w 100% ostrożny, odkąd nazwa może zostać zmutowana, podczas gdy poleganie na łańcuchu prototypów jest mniej kruchy i bardziej idiotyczny OOP. – Sukima

Powiązane problemy