javascript - recorrer - Heredar desde el objeto Error-¿dónde está la propiedad del mensaje?
recorrer array de objetos javascript (7)
¿Qué hay de malo en hacerlo de esta manera en ES6?
class MyError extends Error { constructor(message) { super(message); // Maintains proper stack trace (only on V8) if (Error.captureStackTrace) { Error.captureStackTrace(this, MyError); } this.appcode= 123; // can add custom props } }
Noté un comportamiento extraño al definir objetos de error personalizados en Javascript:
function MyError(msg) {
Error.call(this, msg);
this.name = "MyError";
}
MyError.prototype.__proto__ = Error.prototype;
var error = new Error("message");
error.message; // "message"
var myError = new MyError("message");
myError instanceof Error; // true
myError.message; // "" !
¿Por qué el new Error("message")
establece la propiedad del message
, mientras que Error.call(this, msg);
¿no? Claro, puedo definir this.message = msg
en el constructor MyError
, pero no entiendo por qué no está ya configurado en primer lugar.
En Node.js puedes crear un error personalizado como este:
var util = require(''util'');
function MyError(message) {
this.message = message;
Error.captureStackTrace(this, MyError);
}
util.inherits(MyError, Error);
MyError.prototype.name = ''MyError'';
Consulte captureStackTrace en documentos de nodo
Me gusta mucho crear archivos .js reutilizables que pongo en casi cualquier proyecto en el que participe. Cuando tenga tiempo, se convertirá en un módulo.
Para mis errores, creo un archivo exceptions.js
y lo agrego a mis archivos.
Aquí está el ejemplo del código dentro de este archivo:
const util = require(''util'');
/**
* This exception should be used when some phat of code is not implemented.
* @param {String} message Error message that will be used inside error.
* @inheritDoc Error
*/
function NotImplementedException(message) {
this.message = message;
Error.captureStackTrace(this, NotImplementedException);
}
util.inherits(NotImplementedException, Error);
NotImplementedException.prototype.name = ''NotImplementedException'';
module.exports = {
NotImplementedException,
};
En los otros archivos de mi proyecto, debo tener esta línea requerida en la parte superior del archivo.
const Exceptions = require(''./exceptions.js'');
Y para usar este error solo necesitas esto.
const err = Exceptions.NotImplementedException(`Request token ${requestToken}: The "${operation}" from "${partner}" does not exist.`);
Ejemplo de implementación de método completo
const notImplemented = (requestToken, operation, partner) => {
logger.warn(`Request token ${requestToken}: To "${operation}" received from "${partner}"`);
return new Promise((resolve, reject) => {
const err = Exceptions.NotImplementedException(`Request token ${requestToken}: The "${operation}" from "${partner}" does not exist.`);
logger.error(err.message);
return reject(err);
});
};
Otro enfoque para esto es hacer de la nueva instancia de error el prototipo de this
, y de esa manera no tiene que saber qué propiedades copiar, lo que evita los problemas de los que BT habló al final de su respuesta.
function MyError() {
if (this === undefined) {
throw TypeError("MyError must be called as a constructor");
}
let newErr = Error.apply(undefined, arguments);
Object.setPrototypeOf(newErr, MyError.prototype);
Object.setPrototypeOf(this, newErr);
}
MyError.prototype = Object.create(Error.prototype);
let me = new MyError("A terrible thing happened");
console.log(me instanceof MyError); // true
console.log(me instanceof Error); // true
console.log(me.message); // A terrible thing happened
Y por mi dinero, es un poco mejor. Pero tenga en cuenta que Object.setPrototypeOf()
(u object.__proto__ =
en implementaciones no compatibles con ES6 que lo admiten) puede ser muy lento, por lo que si está utilizando estos errores en sus rutas doradas, es posible que no desee hacerlo.
Puede usar Error.captureStackTrace para filtrar la línea innecesaria en el seguimiento de la pila.
function MyError() {
var tmp = Error.apply(this, arguments);
tmp.name = this.name = ''MyError'';
this.message = tmp.message;
/*this.stack = */Object.defineProperty(this, ''stack'', { // getter for more optimizy goodness
get: function() {
return tmp.stack;
}
});
Error.captureStackTrace(this, MyError); // showing stack trace up to instantiation of Error excluding it.
return this;
}
var IntermediateInheritor = function() {},
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor();
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 ...>
R. Como, dijo Raynos, el message
motivo por el message
no se establece es que Error
es una función que devuelve un nuevo objeto Error y no lo manipula de ninguna manera.
B. La forma de hacerlo bien es establecer el resultado de la aplicación del constructor en this
, así como configurar el prototipo de la manera habitual javascripty complicado:
function MyError() {
var tmp = Error.apply(this, arguments)
tmp.name = this.name = ''MyError''
this.message = tmp.message
// instead of this.stack = ..., a getter for more optimizy goodness
Object.defineProperty(this, ''stack'', {
get: function () {
return tmp.stack
}
})
return this
}
var IntermediateInheritor = function () {}
IntermediateInheritor.prototype = Error.prototype
MyError.prototype = new IntermediateInheritor()
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 ...>
Los únicos problemas con esta forma de hacerlo en este punto (lo he iterado un poco) son que
- las propiedades distintas de la
stack
y elmessage
no están incluidas enMyError
, y - el stacktrace tiene una línea adicional que no es realmente necesaria.
El primer problema podría solucionarse iterando a través de todas las propiedades de error no enumerables usando el truco de esta respuesta: ¿Es posible obtener los nombres de propiedades heredadas no enumerables de un objeto? , pero esto no es compatible con, por ejemplo, <9. El segundo problema podría resolverse arrancando esa línea en el seguimiento de la pila, pero no estoy seguro de cómo hacerlo de manera segura (tal vez simplemente eliminando la segunda línea de e.stack.toString () ??).
Actualizar
Creé una biblioteca de herencia que hace esto ^ https://github.com/fresheneesz/proto
function MyError(msg) {
var err = Error.call(this, msg);
err.name = "MyError";
return err;
}
Error
no lo manipula, crea un nuevo objeto de error que se devuelve. Es por eso que Error("foo")
también funciona sin la new
palabra clave.
Tenga en cuenta que esto es específico de la implementación, v8 (chrome & node.js) se comporta así.
También MyError.prototype.__proto__ = Error.prototype;
es una mala práctica Utilizar
MyError.prototype = Object.create(Error.prototype, {
constructor: { value: MyError }
});