¿Cómo creo un error personalizado en JavaScript?

215

Por alguna razón, parece que la delegación de constructor no funciona en el siguiente fragmento:

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

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

Ejecutar esto da The message is: ''. ¿Alguna idea de por qué, o si hay una mejor manera de crear una nueva Errorsubclase? ¿Hay algún problema con applyel Errorconstructor nativo que no conozco?

cdleary
fuente
¿Funciona la instancia de la instancia NotImplementedError después de los cambios? Pensé que para que esto funcionara necesita definir NotImplementedError.prototype.constructor explícitamente.
jayarjo
La próxima vez, elimine todo el código extraño que no se requiere para demostrar su problema. Además, wtc es js.jar? ¿Es eso necesario para reproducir el problema?
BT
2
Edité esta pregunta para que sea comprensible en 10 segundos en lugar de 10 minutos
BT
Creé
BT
1
jsfiddle para algunas de las mejores respuestas.
Nate

Respuestas:

194

Actualice su código para asignar su prototipo al Error.prototype y la instancia de y sus afirmaciones funcionan.

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

Sin embargo, simplemente lanzaría su propio objeto y simplemente verificaría la propiedad del nombre.

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

Editar basado en comentarios

Después de mirar los comentarios y tratar de recordar por qué asignaría un prototipo en Error.prototypelugar de new Error()como lo hizo Nicholas Zakas en su artículo , creé un jsFiddle con el siguiente código:

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

La salida de la consola fue esta.

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

Esto confirma que el "problema" con el que me encontré fue que la propiedad de pila del error era el número de línea donde new Error()se creó y no dónde throw eocurrió. Sin embargo, eso puede ser mejor que tener el efecto secundario de una NotImplementedError.prototype.name = "NotImplementedError"línea que afecta el objeto Error.

Además, NotImplementedError2tenga en cuenta que , cuando no configuro .nameexplícitamente, es igual a "Error". Sin embargo, como se menciona en los comentarios, debido a que esa versión establece el prototipo new Error(), podría configurar NotImplementedError2.prototype.name = "NotImplementedError2"y estar bien.

Kevin Hakanson
fuente
45
La mejor respuesta, pero tomar Error.prototypedirectamente es probablemente una mala forma. Si más tarde desea agregar un NotImplementedError.prototype.toStringobjeto alias ahora Error.prototype.toString, mejor hacerlo NotImplementedError.prototype = new Error().
cdleary
44
Todavía estoy un poco perdido en todas esas cosas prototipo. ¿Por qué en su ejemplo asigna un nombre a this.name y no a NotImplementedError.prototype.name? ¿Puedes responder por favor, es crucial para mi comprensión :)
jayarjo
27
De acuerdo con code.google.com/p/chromium/issues/detail?id=228909 subclass.prototype = new Error() está en mal estado. Se supone que debes usar subclass.prototype = Object.create(superclass.prototype)en su lugar. Espero que también pueda solucionar el problema de seguimiento de la pila.
Gili
8
El truco simple para obtener un stacktrace significativo es generar un error en el constructor y guardar su stack. Daría una pila de llamadas adecuada + 1 línea para el constructor (es una recompensa adecuada):this.stack = new Error().stack;
Meredian
66
-1; esto está mal. Hacer NotImplementedError.prototype = Error.prototype;no hace instanceoftratar NotImplementedErrorcomo una subclase de Error, hace instanceoftratarlos como exactamente la misma clase. Si pega el código anterior en su consola e intenta new Error() instanceof NotImplementedError, obtendrá true, lo cual es claramente incorrecto.
Mark Amery
87

Todas las respuestas anteriores son terriblemente horribles, de verdad. ¡Incluso el que tiene 107 ups! La verdadera respuesta está aquí chicos:

Heredar del objeto Error: ¿dónde está la propiedad del mensaje?

TL; DR:

R. La razón por la messageque no se establece es que Errores una función que devuelve un nuevo objeto Error y no manipulathis de ninguna manera.

B. La forma de hacer esto bien es devolver el resultado de la aplicación desde el constructor, así como configurar el prototipo de la manera complicada habitual de 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();
*/

Probablemente podría hacer algunos trucos para enumerar todas las propiedades no enumerables del tmpError para establecerlas en lugar de establecerlas explícitamente stacky message, pero el truco no es compatible, es decir, <9

BT
fuente
2
Esta solución también funciona para crear instancias de un error personalizado con un error existente. Si está utilizando una biblioteca de terceros y desea ajustar un error existente con su propio tipo personalizado, los otros métodos no funcionan correctamente. Para su información, puede crear instancias de errores de vainilla pasándoles un error existente.
Kyle Mueller
1
No deberías return thisen un constructor.
Onur Yıldırım
13
Simplifiqué y mejoré un poco este enfoque: jsbin.com/rolojuhuya/1/edit?js,console
Matt Kantor
3
¿@MattKantor quizás haga eso una respuesta? Creo que me gusta más el tuyo.
mpoisot
2
En lugar de temp.name = this.name = 'MyError', puedes hacerlo temp.name = this.name = this.constructor.name. De esa manera también funcionará para subclases de MyError.
Jo Liss
45

En ES2015, puede classhacer esto limpiamente:

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

Esto no modifica el Errorprototipo global , le permite personalizar message,name y otros atributos, y capta adecuadamente la pila. También es bastante legible.

Por supuesto, es posible que deba usar una herramienta como babelsi su código se ejecutara en navegadores más antiguos.

rattray
fuente
23

Si alguien tiene curiosidad sobre cómo crear un error personalizado y obtener el seguimiento de la pila:

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

Esta sección del estándar puede explicar por qué la Error.applyllamada no inicializa el objeto:

15.11.1 El constructor de errores llamado como una función

Cuando se llama a Error como una función en lugar de como un constructor, crea e inicializa un nuevo objeto Error. Por lo tanto, la función llamada Error (...) es equivalente a la expresión de creación de objeto nuevo Error (...) con los mismos argumentos.

En este caso, la Errorfunción probablemente determina que no se llama como un constructor, por lo que devuelve una nueva instancia de Error en lugar de inicializar el thisobjeto.

Las pruebas con el siguiente código parecen demostrar que esto es lo que está sucediendo:

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

La siguiente salida se genera cuando se ejecuta esto:

returned.message = 'some message'
this.message = ''
Dave
fuente
¿Cómo podría simularse esto con una clase de error personalizada? Por ejemplo, ¿cómo podría usarse mi clase de error personalizada como una función que crea una instancia y como un constructor?
Lea Hayes
No, esto no es verdad. Si devuelve una nueva instancia de Error, su propiedad msg funcionaría.
BT
@BT ¿Cómo afecta la propiedad msg en la nueva instancia a la propiedad msg thisen Error.apply(this, arguments);? Estoy diciendo que la llamada al Error aquí está construyendo un nuevo objeto, que se tira; no inicializando el objeto ya construido al que está asignado nie.
Dave
@BT He agregado un código de ejemplo que espero aclare lo que estaba tratando de decir.
Dave
@Dave Puede que haya entendido mal el propósito aquí, pero ¿no debería su NotImplementedErrorimplementación devolver la returnedvariable?
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;
Pierre Voisin
fuente
3
Esta es la mejor respuesta aquí. Es breve y la excepción creada de esta manera se comportará correctamente en todas las situaciones. También conserva el seguimiento de la pila, que es muy importante en aplicaciones no triviales. Solo reemplazaría "prototype = new Error ()" con "prototype = Object.create (Error.prototype)". Para Node.js hay una pequeña biblioteca que hace esto por usted: npmjs.com/package/node-custom-errors
Lukasz Korzybski
6

Tuve un problema similar a esto. Mi error debe ser instanceofambos ErroryNotImplemented , y también debe generar un seguimiento coherente en la consola.

Mi solución:

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

Resultado de ejecutar 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)

El error supera los 3 criterios, y aunque la stackpropiedad no es estándar, es compatible con la mayoría de los navegadores más nuevos, lo cual es aceptable en mi caso.

sinisterchipmunk
fuente
5

Según Joyent, no deberías meterte con la propiedad de la pila (que veo en muchas respuestas aquí), ya que tendrá un impacto negativo en el rendimiento. Aquí está lo que dicen:

stack: en general, no te metas con esto. Ni siquiera lo aumentes. V8 solo lo calcula si alguien realmente lee la propiedad, lo que mejora drásticamente el rendimiento de los errores manejables. Si lees la propiedad solo para aumentarla, terminarás pagando el costo incluso si la persona que llama no necesita la pila.

Me gusta y me gustaría mencionar su idea de envolver el error original que es un buen reemplazo para pasar a la pila.

Así que aquí es cómo creo un error personalizado, teniendo en cuenta lo mencionado anteriormente:

versión 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);
}

versión 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);
}

He puesto mi solución en un módulo, aquí está: https://www.npmjs.com/package/rerror

borisdiakur
fuente
3

Me gusta hacerlo así:

  • Utilice el nombre para que toString () arroje"{code}: {message}"
  • Devuelve lo mismo a super para que aparezca igual en el stacktrace
  • Adjuntar código para error.codeverificar o analizar un código es mejor en código que verificar un mensaje, que quizás desee localizar, por ejemplo
  • Adjuntar mensaje error.messagecomo una 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');
}

Dominic
fuente
2

Simplemente tuve que implementar algo como esto y descubrí que la pila se perdió en mi propia implementación de error. Lo que tuve que hacer fue crear un error ficticio y recuperar la pila de eso:

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;
}
Jules
fuente
Esto no establece el mensaje
BT
2

Usé el patrón de constructor para crear el nuevo objeto de error. Definí la cadena del prototipo como una Errorinstancia. Consulte la referencia del constructor Error MDN .

Puede consultar este fragmento en esta esencia .

IMPLEMENTACIÓN

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

El constructor CustomError puede recibir muchos argumentos para construir el mensaje, p. Ej.

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;

Y así es como se ve el error personalizado:

Cadena de prototipo de error personalizado

jherax
fuente
El que votó en contra, ¿tiene argumentos o una razón para rechazar? o simplemente no entiende la intención en el código.
jherax
Acabo de darme cuenta de que debo haber hecho clic accidentalmente en el botón de votación negativa mientras navegaba por esta página sin darme cuenta (probablemente navegando desde mi teléfono). Solo lo noté hoy mientras navegaba por mi historial. Definitivamente no fue intencional, pero no puedo deshacerlo, ya que ha terminado el período de gracia. Proporcionaste una respuesta informativa y definitivamente no la mereces. Si realiza una edición, felizmente deshaceré el voto negativo. Lo siento por eso.
jschr
1

El constructor debe ser como un método de fábrica y devolver lo que desea. Si necesita métodos / propiedades adicionales, puede agregarlos al objeto antes de devolverlo.

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

x = new NotImplementedError();

Aunque no estoy seguro de por qué necesitarías hacer esto. ¿Por qué no solo usar new Error...? Las excepciones personalizadas realmente no agregan mucho en JavaScript (o probablemente en cualquier lenguaje sin tipo).

Pluckyglen
fuente
2
Debe activar la jerarquía de tipo de error o el valor de objeto en JavaScript porque solo puede especificar un único bloque catch. En su solución, (x instanceof NotImplementedError) es falso, lo cual no es aceptable en mi caso.
cdleary
1

Esto se implementa muy bien en el Cesium DeveloperError:

En su forma simplificada:

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

// Later on...

throw new NotImplementedError();
Aram Kocharyan
fuente
Esto funciona muy bien, excepto que la pila contendrá una línea adicional para el constructor de errores, lo que puede ser un problema.
SystemParadox
Además, no pasa la error instanceof Errorprueba, lo que puede ser útil.
Lauren
1

Esta es mi implementación:

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

Ejemplo de uso # 1:

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

Ejemplo de uso # 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());
  }
});
Rafal Enden
fuente
0

A expensas de no poder usar instanceof, lo siguiente conserva el seguimiento de la pila original y no usa ningún truco no estándar.

// 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
}
Gima
fuente
todo lo que tienes que hacer aquí para poder usar instanceof es lanzar un nuevo fixError en lugar de solo fixError
BT
@BT: no con la fixErrorfunción anterior. Agregar un newal llamarlo simplemente crearía un objeto que se descarta.
TJ Crowder
Oh, supongo que quería decir el uso de "instanceof fixError" -, por supuesto, a continuación, "instanceof error" no funcionaría .. supongo que es peor ..
BT
0

Otra alternativa, podría no funcionar en todos los entornos. Al menos aseguró que funciona en nodejs 0.8 Este enfoque utiliza una forma no estándar de modificar el prototipo interno

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

Si está utilizando Node / Chrome. El siguiente fragmento obtendrá su extensión que cumple con los siguientes requisitos.

  • err instanceof Error
  • err instanceof CustomErrorType
  • console.log () devuelve [CustomErrorType] cuando se crea con un mensaje
  • console.log () regresa [CustomErrorType: message]cuando se crea sin un mensaje
  • throw / stack proporciona la información en el momento en que se creó el error.
  • Funciona de manera óptima en Node.JS y Chrome.
  • Pasará la instancia de los controles en Chrome, Safari, Firefox e IE 8+, pero no tendrá una pila válida fuera de Chrome / Safari. Estoy de acuerdo con eso porque puedo depurar en Chrome, pero el código que requiere tipos de error específicos seguirá funcionando en varios navegadores. Si solo necesita Node, puede eliminar fácilmente las ifdeclaraciones y listo .

Retazo

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

Salida

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
Nucleon
fuente
0

Lo siguiente funcionó para mí tomado de la documentación oficial de Mozilla Error .

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
    }
});
Zhunio
fuente
-1

Pruebe un nuevo objeto prototipo para cada instancia del tipo de error definido por el usuario. Permite que las instanceofcomprobaciones se comporten como de costumbre, además el tipo y el mensaje se informan correctamente en Firefox y 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;
}

Tenga en cuenta que una entrada adicional precederá a la pila correcta.

Augustus Kling
fuente
No funciona Proveedores: var a = new NotImplementedError('a'), b = new NotImplementedError('b');. Ahora a instanceof NotImplementedError == falseyb instanceof NotImplementedError == true
jjrv
-1

Esta es la forma más rápida de hacerlo:

    let thisVar = false

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

De manera más fácil. Puede hacer que su objeto herede del objeto Error. Ejemplo:

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

lo que estamos haciendo es usar la función call () que llama al constructor de la clase Error, por lo que es básicamente lo mismo que implementar una herencia de clase en otros lenguajes orientados a objetos.

Paulo Enmanuel
fuente
-3

MDN tiene un excelente ejemplo :

try {
  throw new Error('Whoops!');
} catch (e) {
  console.log(e.name + ': ' + e.message);
}
Ronnie Royston
fuente