Come posso creare un errore personalizzato in JavaScript?


216

Per qualche motivo sembra che la delega del costruttore non funzioni nel seguente frammento:

function NotImplementedError() { 
  Error.apply(this, arguments); 
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");
console.log("The message is: '"+nie.message+"'")

In esecuzione questo dà The message is: ''. Qualche idea sul perché o se esiste un modo migliore per creare una nuova Errorsottoclasse? C'è un problema con applyil Errorcostruttore nativo che non conosco?


Nie instanceof NotImplementedError assertion funziona dopo le modifiche? Ho pensato che per far funzionare tutto questo è necessario definire esplicitamente NotImplementedError.prototype.constructor.
jayarjo,

La prossima volta, strappare tutto il codice estraneo che non è necessario per dimostrare il problema. Inoltre, wtc è js.jar? È necessario per riprodurre il problema?
BT,

2
Modificato questa domanda in modo che sia comprensibile in 10 secondi anziché 10 minuti
BT

Ho creato una libreria di ereditarietà / classe che eredita correttamente dai tipi di errore: github.com/fresheneesz/proto
BT

1
jsfiddle per alcune delle risposte migliori.
Nate,

Risposte:


194

Aggiorna il tuo codice per assegnare il tuo prototipo a Error.prototype e l'istanza del tuo assert funziona.

function NotImplementedError(message) {
    this.name = "NotImplementedError";
    this.message = (message || "");
}
NotImplementedError.prototype = Error.prototype;

Tuttavia, vorrei solo lanciare il tuo oggetto e controllare solo la proprietà name.

throw {name : "NotImplementedError", message : "too lazy to implement"}; 

Modifica in base ai commenti

Dopo aver esaminato i commenti e aver cercato di ricordare perché avrei assegnato il prototipo Error.prototypeinvece di new Error()come Nicholas Zakas nel suo articolo , ho creato un jsFiddle con il codice seguente:

function NotImplementedError(message) {
  this.name = "NotImplementedError";
  this.message = (message || "");
}
NotImplementedError.prototype = Error.prototype;

function NotImplementedError2(message) {
  this.message = (message || "");
}
NotImplementedError2.prototype = new Error();

try {
  var e = new NotImplementedError("NotImplementedError message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

try {
  var e = new NotImplementedError2("NotImplementedError2 message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError2 = " + (ex1 instanceof NotImplementedError2));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

L'output della console era questo.

undefined
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
Error
    at window.onload (http://fiddle.jshell.net/MwMEJ/show/:29:34)
ex1 instanceof NotImplementedError2 = true
ex1 instanceof Error = true
ex1.name = Error
ex1.message = NotImplementedError2 message

Ciò conferma che il "problema" in cui mi sono imbattuto era la proprietà dello stack dell'errore era il numero di riga in cui è new Error()stato creato e non in cui si è throw everificato. Tuttavia, potrebbe essere meglio che avere l'effetto collaterale di una NotImplementedError.prototype.name = "NotImplementedError"linea che influenza l'oggetto Error.

Inoltre, nota con NotImplementedError2, quando non imposto .nameesplicitamente, è uguale a "Errore". Tuttavia, come menzionato nei commenti, poiché quella versione imposta il prototipo su new Error(), ho potuto impostare NotImplementedError2.prototype.name = "NotImplementedError2"ed essere OK.


45
La migliore risposta, ma prendere Error.prototypedirettamente è probabilmente una cattiva forma. Se in seguito desideri aggiungere un NotImplementedError.prototype.toStringoggetto alias ora Error.prototype.toString- meglio fare NotImplementedError.prototype = new Error().
cdleary,

4
Sono ancora un po 'perso in tutte quelle cose prototipo. Perché nel tuo esempio assegni il nome a this.name e non a NotImplementedError.prototype.name? Puoi rispondere per favore, è fondamentale per la mia comprensione :)
jayarjo

27
Secondo code.google.com/p/chromium/issues/detail?id=228909 subclass.prototype = new Error() è in cattiva forma. Dovresti usare subclass.prototype = Object.create(superclass.prototype)invece. Spero che possa risolvere anche il problema dello stack-trace.
Gili,

8
Un semplice trucco per ottenere una stacktrace significativa è generare errori nel costruttore e salvarne lo stack. this.stack = new Error().stack;
Darebbe lo

6
-1; questo è sbagliato. Fare NotImplementedError.prototype = Error.prototype;non instanceoftratta NotImplementedErrorcome una sottoclasse di Error, instanceofli considera esattamente la stessa classe. Se incolli il codice sopra nella tua console e provi new Error() instanceof NotImplementedError, otterrai true, il che è chiaramente sbagliato.
Mark Amery,

87

Tutte le risposte di cui sopra sono terribilmente terribili - davvero. Anche quello con 107 up! La vera risposta è qui ragazzi:

Ereditando dall'oggetto Error - dov'è la proprietà message?

TL; DR:

R. Il motivo per cui messagenon viene impostato è che Errorè una funzione che restituisce un nuovo oggetto Error e non si manipola thisin alcun modo.

B. Il modo per farlo nel modo giusto è quello di restituire il risultato dell'applicazione dal costruttore, oltre a impostare il prototipo nel solito modo complicato javascripty:

function MyError() {
    var temp = Error.apply(this, arguments);
    temp.name = this.name = 'MyError';
    this.message = temp.message;
    if(Object.defineProperty) {
        // getter for more optimizy goodness
        /*this.stack = */Object.defineProperty(this, 'stack', { 
            get: function() {
                return temp.stack
            },
            configurable: true // so you can change it if you want
        })
    } else {
        this.stack = temp.stack
    }
}
//inherit prototype using ECMAScript 5 (IE 9+)
MyError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: MyError,
        writable: true,
        configurable: true
    }
});

var myError = new MyError("message");
console.log("The message is: '" + myError.message + "'"); // The message is: 'message'
console.log(myError instanceof Error); // true
console.log(myError instanceof MyError); // true
console.log(myError.toString()); // MyError: message
console.log(myError.stack); // MyError: message \n 
// <stack trace ...>


 
//for EMCAScript 4 or ealier (IE 8 or ealier), inherit prototype this way instead of above code:
/*
var IntermediateInheritor = function() {};
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor();
*/

Probabilmente potresti fare qualche trucco per enumerare tutte le proprietà non enumerabili tmpdell'errore per impostarle piuttosto che impostarle esplicitamente stacke message, ma il trucco non è supportato in <9


2
Questa soluzione funziona anche per istanziare un errore personalizzato con un errore esistente. Se stai utilizzando una libreria di terze parti e desideri racchiudere un errore esistente con il tuo tipo personalizzato, gli altri metodi non funzionano correttamente. Cordiali saluti, è possibile creare un'istanza di errori vanilla passando loro un errore esistente.
Kyle Mueller,

1
non dovresti essere return thisin un costruttore.
Onur Yıldırım,

13
Ho semplificato e migliorato un po 'questo approccio: jsbin.com/rolojuhuya/1/edit?js,console
Matt Kantor,

3
@MattKantor potrebbe forse dare una risposta? Penso che mi piaccia il tuo meglio.
mpoisot,

2
Invece di temp.name = this.name = 'MyError', puoi farlo temp.name = this.name = this.constructor.name. In questo modo funzionerà anche per le sottoclassi MyError.
Jo Liss,

45

In ES2015, è possibile utilizzare classper farlo in modo pulito:

class NotImplemented extends Error {
  constructor(message = "", ...args) {
    super(message, ...args);
    this.message = message + " has not yet been implemented.";
  }
}

Ciò non modifica il Errorprototipo globale , ti consente di personalizzare message,name e altri attributi, e cattura adeguatamente la pila. È anche abbastanza leggibile.

Naturalmente, potrebbe essere necessario utilizzare uno strumento come babelse il codice verrà eseguito su browser meno recenti.


23

Se qualcuno è curioso di sapere come creare un errore personalizzato e ottenere la traccia dello stack:

function CustomError(message) {
  this.name = 'CustomError';
  this.message = message || '';
  var error = new Error(this.message);
  error.name = this.name;
  this.stack = error.stack;
}
CustomError.prototype = Object.create(Error.prototype);

try {
  throw new CustomError('foobar');
}
catch (e) {
  console.log('name:', e.name);
  console.log('message:', e.message);
  console.log('stack:', e.stack);
}

7

Questa sezione dello standard può spiegare perché la Error.applychiamata non inizializza l'oggetto:

15.11.1 Il costruttore dell'errore chiamato come funzione

Quando viene chiamato Errore come funzione anziché come costruttore, crea e inizializza un nuovo oggetto Errore. Pertanto, la chiamata alla funzione Errore (...) equivale all'espressione di creazione dell'oggetto nuovo Errore (...) con gli stessi argomenti.

In questo caso Error, probabilmente la funzione determina che non viene chiamato come costruttore, quindi restituisce una nuova istanza di errore anziché inizializzare l' thisoggetto.

Testare con il seguente codice sembra dimostrare che questo è effettivamente ciò che sta accadendo:

function NotImplementedError() { 
   var returned = Error.apply(this, arguments);
   console.log("returned.message = '" + returned.message + "'");
   console.log("this.message = '" + this.message + "'");
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");

Il seguente output viene generato quando viene eseguito:

returned.message = 'some message'
this.message = ''

come è possibile simularlo con una classe di errore personalizzata? Ad esempio, come è possibile utilizzare la mia classe di errore personalizzata sia come funzione che crea un'istanza sia come costruttore?
Lea Hayes,

No, questo non è vero. Se restituiva una nuova istanza di errore, la sua proprietà msg funzionava.
BT,

@BT In che modo la proprietà msg sulla nuova istanza influenza la proprietà msg su thisin Error.apply(this, arguments);? Sto dicendo che la chiamata a Error qui sta costruendo un nuovo oggetto, che viene gettato via; non inizializzare l'oggetto già costruito a cui è assegnato nie.
Dave,

@BT Ho aggiunto un codice di esempio che, si spera, chiarisce cosa stavo cercando di dire.
Dave,

@Dave Potrei aver frainteso lo scopo qui, ma la tua NotImplementedErrorimplementazione non dovrebbe restituire la returnedvariabile?
blong

7
function InvalidValueError(value, type) {
    this.message = "Expected `" + type.name + "`: " + value;
    var error = new Error(this.message);
    this.stack = error.stack;
}
InvalidValueError.prototype = new Error();
InvalidValueError.prototype.name = InvalidValueError.name;
InvalidValueError.prototype.constructor = InvalidValueError;

3
Questa è la migliore risposta qui. È succint e l'eccezione creata in questo modo si comporterà correttamente in tutte le situazioni. Conserva anche la traccia dello stack che è molto importante in applicazioni non banali. Sostituirei solo "prototype = new Error ()" con "prototype = Object.create (Error.prototype)". Per Node.js c'è una piccola libreria che fa questo per te: npmjs.com/package/node-custom-errors
Lukasz Korzybski

6

Ho avuto un problema simile a questo. Il mio errore deve essere un instanceofentrambi ErroreNotImplemented deve anche produrre un backtrace coerente nella console.

La mia soluzione:

var NotImplemented = (function() {
  var NotImplemented, err;
  NotImplemented = (function() {
    function NotImplemented(message) {
      var err;
      err = new Error(message);
      err.name = "NotImplemented";
      this.message = err.message;
      if (err.stack) this.stack = err.stack;
    }
    return NotImplemented;
  })();
  err = new Error();
  err.name = "NotImplemented";
  NotImplemented.prototype = err;

  return NotImplemented;
}).call(this);

// TEST:
console.log("instanceof Error: " + (new NotImplemented() instanceof Error));
console.log("instanceof NotImplemented: " + (new NotImplemented() instanceofNotImplemented));
console.log("message: "+(new NotImplemented('I was too busy').message));
throw new NotImplemented("just didn't feel like it");

Risultato dell'esecuzione con node.js:

instanceof Error: true
instanceof NotImplemented: true
message: I was too busy

/private/tmp/t.js:24
throw new NotImplemented("just didn't feel like it");
      ^
NotImplemented: just didn't feel like it
    at Error.NotImplemented (/Users/colin/projects/gems/jax/t.js:6:13)
    at Object.<anonymous> (/Users/colin/projects/gems/jax/t.js:24:7)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:487:10)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

L'errore supera tutti e 3 i miei criteri e, sebbene la stackproprietà non sia standard, è supportata nella maggior parte dei browser più recenti, il che è accettabile nel mio caso.


5

Accogliendo Joyent non dovresti fare casini con la proprietà dello stack (che vedo in molte risposte fornite qui), perché avrà un impatto negativo sulle prestazioni. Ecco cosa dicono:

stack: generalmente non scherzare con questo. Non aumentarlo nemmeno. V8 lo calcola solo se qualcuno legge effettivamente la proprietà, migliorando notevolmente le prestazioni per errori gestibili. Se leggi la proprietà solo per aumentarla, finirai per pagare il costo anche se il tuo chiamante non ha bisogno dello stack.

Mi piace e vorrei menzionare la loro idea di avvolgere l'errore originale che è un buon rimpiazzo per passare in pila.

Quindi ecco come creo un errore personalizzato, considerando quanto sopra menzionato:

versione es5:

function RError(options) {
    options = options || {}; // eslint-disable-line no-param-reassign
    this.name = options.name;
    this.message = options.message;
    this.cause = options.cause;

    // capture stack (this property is supposed to be treated as private)
    this._err = new Error();

    // create an iterable chain
    this.chain = this.cause ? [this].concat(this.cause.chain) : [this];
}
RError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: RError,
        writable: true,
        configurable: true
    }
});

Object.defineProperty(RError.prototype, 'stack', {
    get: function stack() {
        return this.name + ': ' + this.message + '\n' + this._err.stack.split('\n').slice(2).join('\n');
    }
});

Object.defineProperty(RError.prototype, 'why', {
    get: function why() {
        var _why = this.name + ': ' + this.message;
        for (var i = 1; i < this.chain.length; i++) {
            var e = this.chain[i];
            _why += ' <- ' + e.name + ': ' + e.message;
        }
        return _why;
    }
});

// usage

function fail() {
    throw new RError({
        name: 'BAR',
        message: 'I messed up.'
    });
}

function failFurther() {
    try {
        fail();
    } catch (err) {
        throw new RError({
            name: 'FOO',
            message: 'Something went wrong.',
            cause: err
        });
    }
}

try {
    failFurther();
} catch (err) {
    console.error(err.why);
    console.error(err.stack);
    console.error(err.cause.stack);
}

versione es6:

class RError extends Error {
    constructor({name, message, cause}) {
        super();
        this.name = name;
        this.message = message;
        this.cause = cause;
    }
    [Symbol.iterator]() {
        let current = this;
        let done = false;
        const iterator = {
            next() {
                const val = current;
                if (done) {
                    return { value: val, done: true };
                }
                current = current.cause;
                if (!val.cause) {
                    done = true;
                }
                return { value: val, done: false };
            }
        };
        return iterator;
    }
    get why() {
        let _why = '';
        for (const e of this) {
            _why += `${_why.length ? ' <- ' : ''}${e.name}: ${e.message}`;
        }
        return _why;
    }
}

// usage

function fail() {
    throw new RError({
        name: 'BAR',
        message: 'I messed up.'
    });
}

function failFurther() {
    try {
        fail();
    } catch (err) {
        throw new RError({
            name: 'FOO',
            message: 'Something went wrong.',
            cause: err
        });
    }
}

try {
    failFurther();
} catch (err) {
    console.error(err.why);
    console.error(err.stack);
    console.error(err.cause.stack);
}

Ho inserito la mia soluzione in un modulo, eccolo qui: https://www.npmjs.com/package/rerror


3

Mi piace farlo così:

  • Usa il nome modo che passi aString ()"{code}: {message}"
  • Ritorna la stessa cosa su super in modo che appaia la stessa nello stacktrace
  • Allega codice a error.code come controllo / analisi di un codice è meglio nel codice rispetto al controllo di un messaggio, che potresti voler localizzare per esempio
  • Allega messaggio a error.messagein alternativa aerror.toString()

class AppException extends Error {
  constructor(code, message) {
    const fullMsg = message ? `${code}: ${message}` : code;
    super(fullMsg);
    this.name = code;
    this.code = code;
    this.message = fullMsg;
  }
  
  toString() {
    return this.message;
  }
}

// Just a code
try {
  throw new AppException('FORBIDDEN');
} catch(e) {
  console.error(e);
  console.error(e.toString());
  console.log(e.code === 'FORBIDDEN');
}

// A code and a message
try {
  throw new AppException('FORBIDDEN', 'You don\'t have access to this page');
} catch(e) {
  console.error(e);
  console.error(e.toString());
  console.log(e.code === 'FORBIDDEN');
}


2

Ho dovuto solo implementare qualcosa del genere e ho scoperto che lo stack era perso nella mia implementazione dell'errore. Quello che dovevo fare era creare un errore fittizio e recuperare lo stack da quello:

My.Error = function (message, innerException) {
    var err = new Error();
    this.stack = err.stack; // IMPORTANT!
    this.name = "Error";
    this.message = message;
    this.innerException = innerException;
}
My.Error.prototype = new Error();
My.Error.prototype.constructor = My.Error;
My.Error.prototype.toString = function (includeStackTrace) {
    var msg = this.message;
    var e = this.innerException;
    while (e) {
        msg += " The details are:\n" + e.message;
        e = e.innerException;
    }
    if (includeStackTrace) {
        msg += "\n\nStack Trace:\n\n" + this.stack;
    }
    return msg;
}

Questo non imposta il messaggio
BT

2

Ho usato il modello di costruzione per creare il nuovo oggetto errore. Ho definito la catena di prototipi come Errorun'istanza. Vedere il costruttore Errore MDN riferimento del .

Puoi controllare questo frammento su questo argomento .

IMPLEMENTAZIONE

// Creates user-defined exceptions
var CustomError = (function() {
  'use strict';

  //constructor
  function CustomError() {
    //enforces 'new' instance
    if (!(this instanceof CustomError)) {
      return new CustomError(arguments);
    }
    var error,
      //handles the arguments object when is passed by enforcing a 'new' instance
      args = Array.apply(null, typeof arguments[0] === 'object' ? arguments[0] : arguments),
      message = args.shift() || 'An exception has occurred';

    //builds the message with multiple arguments
    if (~message.indexOf('}')) {
      args.forEach(function(arg, i) {
        message = message.replace(RegExp('\\{' + i + '}', 'g'), arg);
      });
    }

    //gets the exception stack
    error = new Error(message);
    //access to CustomError.prototype.name
    error.name = this.name;

    //set the properties of the instance
    //in order to resemble an Error instance
    Object.defineProperties(this, {
      stack: {
        enumerable: false,
        get: function() { return error.stack; }
      },
      message: {
        enumerable: false,
        value: message
      }
    });
  }

  // Creates the prototype and prevents the direct reference to Error.prototype;
  // Not used new Error() here because an exception would be raised here,
  // but we need to raise the exception when CustomError instance is created.
  CustomError.prototype = Object.create(Error.prototype, {
    //fixes the link to the constructor (ES5)
    constructor: setDescriptor(CustomError),
    name: setDescriptor('JSU Error')
  });

  function setDescriptor(value) {
    return {
      configurable: false,
      enumerable: false,
      writable: false,
      value: value
    };
  }

  //returns the constructor
  return CustomError;
}());

USO

Il costruttore CustomError può ricevere molti argomenti per creare il messaggio, ad es

var err1 = new CustomError("The url of file is required"),
    err2 = new CustomError("Invalid Date: {0}", +"date"),
    err3 = new CustomError("The length must be greater than {0}", 4),
    err4 = new CustomError("Properties .{0} and .{1} don't exist", "p1", "p2");

throw err4;

Ed ecco come appare l'errore personalizzato:

Catena di prototipi di errori personalizzati


Colui che ha votato per il down, hai degli argomenti o un motivo per votare? o semplicemente non capisce l'intenzione nel codice.
jherax,

Ho appena notato che devo aver accidentalmente fatto clic sul pulsante downvote durante la navigazione di questa pagina senza rendermene conto (probabilmente navigando dal mio telefono). L'ho notato solo oggi mentre sfogliavo la mia cronologia. Sicuramente non è stato intenzionale, ma non posso annullarlo perché è durante il periodo di grazia. Hai fornito una risposta informativa e sicuramente non te lo meriti. Se fai una modifica, annullerò felicemente il downvote. Mi dispiace per quello.
jschr,

1

Il costruttore deve essere come un metodo di fabbrica e restituire ciò che desideri. Se sono necessari ulteriori metodi / proprietà, è possibile aggiungerli all'oggetto prima di restituirlo.

function NotImplementedError(message) { return new Error("Not implemented", message); }

x = new NotImplementedError();

Anche se non sono sicuro del motivo per cui dovresti farlo. Perché non usare solo new Error...? Le eccezioni personalizzate non aggiungono molto in JavaScript (o probabilmente in qualsiasi linguaggio non tipizzato).


2
Devi attivare la gerarchia del tipo di errore o il valore dell'oggetto in JavaScript perché puoi specificare un solo blocco catch. Nella tua soluzione, (x instanceof NotImplementedError) è falso, il che non è accettabile nel mio caso.
cdleary,

1

Questo è implementato bene nell'errore Developer Cesium:

Nella sua forma semplificata:

var NotImplementedError = function(message) {
    this.name = 'NotImplementedError';
    this.message = message;
    this.stack = (new Error()).stack;
}

// Later on...

throw new NotImplementedError();

Funziona alla grande, tranne per il fatto che lo stack conterrà una riga aggiuntiva per il costruttore dell'errore, che può essere un problema.
SystemParadox,

Inoltre, non supera il error instanceof Errortest, il che può essere utile.
Lauren,

1

Questa è la mia implementazione:

class HttpError extends Error {
  constructor(message, code = null, status = null, stack = null, name = null) {
    super();
    this.message = message;
    this.status = 500;

    this.name = name || this.constructor.name;
    this.code = code || `E_${this.name.toUpperCase()}`;
    this.stack = stack || null;
  }

  static fromObject(error) {
    if (error instanceof HttpError) {
      return error;
    }
    else {
      const { message, code, status, stack } = error;
      return new ServerError(message, code, status, stack, error.constructor.name);
    }
  }

  expose() {
    if (this instanceof ClientError) {
      return { ...this };
    }
    else {
      return {
        name: this.name,
        code: this.code,
        status: this.status,
      }
    }
  }
}

class ServerError extends HttpError {}

class ClientError extends HttpError { }

class IncorrectCredentials extends ClientError {
  constructor(...args) {
    super(...args);
    this.status = 400;
  }
}

class ResourceNotFound extends ClientError {
  constructor(...args) {
    super(...args);
    this.status = 404;
  }
}

Esempio di utilizzo n. 1:

app.use((req, res, next) => {
  try {
    invalidFunction();
  }
  catch (err) {
    const error = HttpError.fromObject(err);
    return res.status(error.status).send(error.expose());
  }
});

Esempio di utilizzo n. 2:

router.post('/api/auth', async (req, res) => {
  try {
    const isLogged = await User.logIn(req.body.username, req.body.password);

    if (!isLogged) {
      throw new IncorrectCredentials('Incorrect username or password');
    }
    else {
      return res.status(200).send({
        token,
      });
    }
  }
  catch (err) {
    const error = HttpError.fromObject(err);
    return res.status(error.status).send(error.expose());
  }
});

0

A scapito di non poterlo utilizzare instanceof, quanto segue conserva la traccia dello stack originale e non utilizza trucchi non standard.

// the function itself
var fixError = function(err, name) {
    err.name = name;
    return err;
}

// using the function
try {
    throw fixError(new Error('custom error message'), 'CustomError');
} catch (e) {
    if (e.name == 'CustomError')
        console.log('Wee! Custom Error! Msg:', e.message);
    else
        throw e; // unhandled. let it propagate upwards the call stack
}

tutto quello che devi fare qui per essere in grado di usare instanceof è lanciare una nuova correzioneError invece che solo fixError
BT

@BT: non con la fixErrorfunzione sopra. Aggiungendo un newquando lo chiami, si creerebbe semplicemente un oggetto che viene gettato via.
TJ Crowder,

Oh, suppongo che intendevo usare "instanceof fixError" - ovviamente allora "instanceof Error" non avrebbe funzionato .. suppongo che sia peggio ..
BT

0

Un'altra alternativa, potrebbe non funzionare in tutti gli ambienti. Almeno assicurato che funzioni in nodejs 0.8 Questo approccio utilizza un modo non standard di modificare il prototipo interno

function myError(msg){ 
      var e = new Error(msg); 
      _this = this; 
      _this.__proto__.__proto__ = e;
}

0

Se si utilizza Nodo / Chrome. Il frammento seguente ti darà l'estensione che soddisfa i seguenti requisiti.

  • err instanceof Error
  • err instanceof CustomErrorType
  • console.log () restituisce [CustomErrorType] quando viene creato con un messaggio
  • console.log () restituisce [CustomErrorType: message]quando viene creato senza un messaggio
  • throw / stack fornisce le informazioni nel punto in cui è stato creato l'errore.
  • Funziona in modo ottimale in Node.JS e Chrome.
  • Passerà i controlli di instanceof in Chrome, Safari, Firefox e IE 8+, ma non avrà uno stack valido al di fuori di Chrome / Safari. Sono d'accordo con questo perché posso eseguire il debug in Chrome, ma il codice che richiede tipi di errore specifici funzionerà comunque tra i browser. Se hai bisogno solo di Node puoi rimuovere facilmente le ifistruzioni e sei a posto .

Frammento

var CustomErrorType = function(message) {
    if (Object.defineProperty) {
        Object.defineProperty(this, "message", {
            value : message || "",
            enumerable : false
        });
    } else {
        this.message = message;
    }

    if (Error.captureStackTrace) {
        Error.captureStackTrace(this, CustomErrorType);
    }
}

CustomErrorType.prototype = new Error();
CustomErrorType.prototype.name = "CustomErrorType";

uso

var err = new CustomErrorType("foo");

Produzione

var err = new CustomErrorType("foo");
console.log(err);
console.log(err.stack);

[CustomErrorType: foo]
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

/errorTest.js:30
        throw err;
              ^
CustomErrorType: foo
    at Object.<anonymous> (/errorTest.js:27:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

0

Di seguito ha lavorato per me preso dalla documentazione ufficiale di Mozilla errore .

function NotImplementedError(message) {
    var instance = new Error(message);
    instance.name = 'NotImplementedError';

    Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
    if (Error.captureStackTrace) {
        Error.captureStackTrace(instance, NotImplementedError);
    }
    return instance;
}

NotImplementedError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: Error,
        enumerable: false,
        writable: true,
        configurable: true
    }
});

-1

Prova un nuovo oggetto prototipo per ogni istanza del tipo di errore definito dall'utente. Consente ai instanceofcontrolli di comportarsi come al solito, inoltre il tipo e il messaggio sono riportati correttamente in Firefox e V8 (Chome, nodejs).

function NotImplementedError(message){
    if(NotImplementedError.innercall===undefined){
        NotImplementedError.innercall = true;
        NotImplementedError.prototype = new Error(message);
        NotImplementedError.prototype.name = "NotImplementedError";
        NotImplementedError.prototype.constructor = NotImplementedError;

        return new NotImplementedError(message);
    }
    delete NotImplementedError.innercall;
}

Si noti che una voce aggiuntiva precederà lo stack altrimenti corretto.


Non funziona Prova: var a = new NotImplementedError('a'), b = new NotImplementedError('b');. Ora a instanceof NotImplementedError == falseeb instanceof NotImplementedError == true
jjrv il

-1

Questo è il modo più veloce per farlo:

    let thisVar = false

    if (thisVar === false) {
            throw new Error("thisVar is false. It should be true.")
    }

-3

modo più semplice. È possibile rendere il tuo oggetto ereditato dall'oggetto Error. Esempio:

function NotImplementError(message)
{
    this.message = message;
    Error.call();
    Error.call(message);
} 

quello che stiamo facendo è usare la funzione call () che chiama il costruttore della classe Error, quindi è sostanzialmente la stessa cosa dell'implementazione di un'eredità di classe in altri linguaggi orientati agli oggetti.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.