2012-01-29 12 views
29

qualche modo questo non si sente come il culmine di 50 anni di programmazione lo sviluppo del linguaggio:corretta non stringa JavaScript eccezioni

throw "My exception message here"; 

Qual è il modo corretto di fare eccezioni in Javascript, in modo che

  • Possono essere identificati (instanceof)

  • Possono trasportare altro payload oltre al messaggio predefinito e stack trace

  • Essi "sottoclasse" base Exception, in modo che console di debug e tali in grado di estrarre informazioni significative sulla eccezione

  • possibili eccezioni nidificate (conversione eccezione a un'altra): se avete bisogno di catturare un'eccezione e rigenerare nuovo uno l'analisi dello stack orignal sarebbe stato conservato e potrebbe essere significato letta da strumenti di debug

  • seguono Javascript migliori pratiche

+0

JavaScript non ha davvero questi? Puoi serializzare qualsiasi oggetto in una stringa in JS? –

+2

@VladislavZorov: Sì, il Javascript ha questi. –

+0

Chiarito la necessità di eccezioni nidificate –

risposta

25

throw new Error("message");

o se si vuole essere più specifico, utilizzare uno dei Error Objects

E 'importante assicurarsi che si passi veri e propri errori perché contengono la traccia dello stack. Lanciare una stringa è stupido perché non ha alcun metadati ad esso collegato.

È possibile anche errori sottoclasse

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

"per una ragionevole implementazione di estensione" cosa? Non capisco –

+3

Il modello di estensione di estensione JavaScript è un modello di progettazione comune implementato da molti framework Javascript, ad es. jQuery http://api.jquery.com/jQuery.extend/ –

+0

@Mikko: Sì, lo so, ma non ottengo quella frase. Non manca qualcosa? –

9

una base di "eccezione" in JavaScript è Bui lt-in Error oggetto:

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

è possibile definire le eccezioni personalizzate come:

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

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

Controllare tipo di eccezione con instanceof. C'è anche un handy list of built-in exceptions.

+5

Evita di chiamare 'new Error' nell'assegnazione' CustomError' quando richiama il costruttore su 'CustomError' lasciando dietro di sé i dati di traccia dello stack. Preferisci l'utilizzo dell'estensione Prototypical ('CustomError.prototype = Object.create (Error);') – Raynos

+0

@Raynos Perché usi Object.create (Error) invece di new Error? Potresti chiarire la differenza tra i due? – radicalmatt

2

È possibile creare un oggetto Error chiamando lo Error constructor. Un oggetto error può avere un messaggio e un nome. Durante la cattura è possibile verificare la presenza di un nome specifico o creare un tipo di errore personalizzato ereditando il prototipo Error. Ciò consente l'utilizzo di instanceof tra i diversi tipi di errore.

// 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" 
} 

Esempio tratto da: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error

+2

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

+0

@Raynos In un ambiente del browser 'Object.create' potrebbe non essere disponibile e avresti bisogno di un polyfill. In un ambiente JavaScript> = 1.8.5 sono d'accordo. – Eliasdx

+1

è ancora meglio polyfill Object.create quindi usare 'new y();' – Raynos

3

Non si può farlo, e soddisfano i requisiti di domanda.

Perché?

Il problema è ottenere lo stack. Oggetto di errore nativo (NativeError da ora in poi), inizializza lo stack quando viene chiamato il suo costruttore.Per ottenere lo stack in MyError (la sottoclasse di errore), devi chiamare il NativeConstructor all'interno del costruttore di MyError. Quindi, la classe MyError è simile a questa:

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

Ma, questo non funziona. Perché in base alle specifiche HTML5:

"se si chiama Errore come funzione, restituisce un nuovo oggetto Errore".

Anziché il costruttore di Error sta eseguendo il comando e inizializzando la classe di errore personalizzata, crea un errore che non si utilizza per. Non ho trovato un modo per chiamare il costruttore NativeError e farlo inizializzare sottoclasse MyError.

Non tutto è perduto.

Se rilassiamo i requisiti della domanda originale e dimentichiamo "instanceof" per testare la classe di eccezioni (quindi Java comunque) e usare "nome", invece, è possibile farlo. Dichiara MyError come:

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

Questo è quello che faccio. Invece di attivare "instanceof", attiva invece "name".

+0

Non tutte le librerie rispettano la variabile 'name'. [Bluebird] (http://bluebirdjs.com/docs/api/catch.html), ad esempio, richiede un errore personalizzato 'prototype' per discendere da' Error.prototype'. In effetti, a seconda dello stato di un oggetto, puoi metterti nei guai se non sei attento al 100% poiché il nome può essere mutato mentre fare affidamento su una catena di prototipi è meno fragile e più idiologico OOP. – Sukima

Problemi correlati