Quiero lanzar algunas cosas en mi código JS y quiero que sean instanceof Error, pero también quiero que sean otra cosa.
En Python, típicamente, uno subclasificaría Exception.
¿Qué hay que hacer en JS?
El único campo estándar que tiene el objeto Error es la propiedad message
. (Ver MDN, o Especificación del Lenguaje EcmaScript, sección 15.11) Todo lo demás es específico de la plataforma.
La mayoría de los entornos establecen la propiedad stack
, pero fileName
y lineNumber
son prácticamente inútiles para ser usadas en herencia.
Por lo tanto, el enfoque minimalista es:
function MyError(message) {
this.name = 'MyError';
this.message = message;
this.stack = (new Error()).stack;
}
MyError.prototype = new Error; // <-- remove this if you do not
// want MyError to be instanceof Error
Usted podría olfatear la pila, desalojar los elementos no deseados de la misma y extraer información como fileName y lineNumber, pero para ello se requiere información acerca de la plataforma JavaScript se está ejecutando en la actualidad. En la mayoría de los casos eso es innecesario -- y puedes hacerlo en post-mortem si realmente quieres.
Safari es una notable excepción. No hay propiedad stack
, pero la palabra clave throw
establece las propiedades sourceURL
y line
del objeto que está siendo lanzado. Esas cosas están garantizadas para ser correctas.
Los casos de prueba que utilicé se pueden encontrar aquí: JavaScript self-made Error object comparison.
La respuesta altamente votada de Crescent Fresh's es engañosa. Aunque sus advertencias no son válidas, hay otras limitaciones que no aborda.
En primer lugar, el razonamiento en Crescent's "Caveats:" párrafo doesn't tiene sentido. La explicación implica que la codificación "un montón de if (error instanceof MyError) else ..." es de alguna manera onerosa o verbosa en comparación con múltiples sentencias catch. Múltiples sentencias instanceof en un solo bloque catch son tan concisas como múltiples sentencias catch-- código limpio y conciso sin trucos. Esta es una gran manera de emular el gran manejo de errores específico de Java.
WRT "parece que la propiedad message de la subclase no se establece", ese no es el caso si se utiliza una subclase Error correctamente construida. Para hacer su propia subclase ErrorX Error, sólo tiene que copiar el bloque de código que comienza con "var MiError =", cambiando la única palabra "MiError" por "ErrorX". (Si desea añadir métodos personalizados a su subclase, siga el texto de ejemplo).
La limitación real y significativa de la subclase de error de JavaScript es que para las implementaciones o depuradores de JavaScript que rastrean e informan sobre el seguimiento de pila y la ubicación de la instanciación, como FireFox, una ubicación en su propia implementación de la subclase Error se registrará como el punto de instanciación de la clase, mientras que si utilizara un Error directo, sería la ubicación donde ejecutó "new Error(...)"). Los usuarios de IE probablemente nunca lo notarán, pero los usuarios de Fire Bug en FF verán valores inútiles de nombre de archivo y número de línea reportados junto a estos Errores, y tendrán que profundizar en el rastreo de pila hasta el elemento #1 para encontrar la ubicación real de instanciación.
En el ejemplo anterior Error.apply
(también Error.call
) no me hace nada (Firefox 3.6/Chrome 5). Una solución que utilizo es:
function MyError(message, fileName, lineNumber) {
var err = new Error();
if (err.stack) {
// remove one stack level:
if (typeof(Components) != 'undefined') {
// Mozilla:
this.stack = err.stack.substring(err.stack.indexOf('\n')+1);
}
else if (typeof(chrome) != 'undefined' || typeof(process) != 'undefined') {
// Google Chrome/Node.js:
this.stack = err.stack.replace(/\n[^\n]*/,'');
}
else {
this.stack = err.stack;
}
}
this.message = message === undefined ? err.message : message;
this.fileName = fileName === undefined ? err.fileName : fileName;
this.lineNumber = lineNumber === undefined ? err.lineNumber : lineNumber;
}
MyError.prototype = new Error();
MyError.prototype.constructor = MyError;
MyError.prototype.name = 'MyError';