在由深度npm依赖关系构造函数创build的对象上使用`instanceof`
背景:
我有一个npm模块,我有常见的error handling代码,包括一个自定义错误:
function CustomError () { /* ... */ } CustomError.prototype = Object.create(Error.prototype); CustomError.prototype.constructor = CustomError; module.exports = CustomError;
我有一些其他的模块(我们称之为'module-a'和'module-b' ),这两个模块都依赖于error handling模块。
我也有一些使用蓝鸟“过滤捕捉”function的代码:
doSomething .catch(CustomError, () => { /* ... */ });
问题:
经过一些debugging后,我发现(在事后看来)在'module-a'中创build的错误不是由'module-b'创build的错误的实例。 这是因为两个模块都有自己的包含CustomError
构造函数的JS文件副本,这两个模块都是独立运行的。
我宁愿不必诉诸于我目前的解决scheme,这基本上是:
CustomError.isCustomError = e => e.constructor.toString() === CustomError.toString();
接着:
doSomething .then(CustomError.isCustomError, () => { /* ... */ });
这显然是脆弱的,如果版本不同步,将会崩溃。
所以…
有一些方法可以确保'module-a'和'module-b'都使用构造函数的相同实例吗? 或者另一个较脆弱的解决scheme。
这实际上也是浏览器的一个问题,当你有一个iframe的时候,它会得到它自己的副本,例如,数组构造函数(使instanceof
无用)。
自定义构造函数的解决scheme是鸭式input。 这里有一些潜在的利弊解决scheme。
-
检查构造函数名称。 Pro:简单,支持良好。 Con:最好选一个相当独特的名字来避免误报,并忘记对它进行分类。
-
检查对象的属性(例如同时具有“foo”和“bar”和“foo”是一个函数)。 临:大多是防呆的。 缺点:易碎:如果您重构自定义错误类,则此检查可能会随机中断,而且相对昂贵。
-
(推荐)添加属性/方法。 这是一些库(例如,moment.js)如何处理这个问题。
代码示例:
CustomError.prototype._isCustomError = true; var isCustomError = function isCustomError(obj) { return obj instanceof CustomError || Boolean(obj._isCustomError); }; module.exports = { CustomError, isCustomError };
这或多或less地是如何检测给定对象是否是时刻对象的时刻。
你是什么意思:
经过一些debugging后,我发现(在事后看来)在'module-a'中创build的错误不是由'module-b'创build的错误的实例。
错误对象不能是另一个错误对象的实例。 或者你是说,当执行像err instanceof CustomError
这样的错误从module-a
err instanceof CustomError
或module-b
返回不同的结果? 考虑到instanceof
在对象的原型链中testing了constructor.prototype
存在,那么当您再次testingCustomError
时,这些模块中的错误应该通过您发布的代码返回true
。
你能告诉你如何在这些模块中创build这些错误吗?
这是因为两个模块都有自己的包含CustomError构造函数的JS文件副本,这两个模块都是独立运行的。
再一次,我很困惑这个声明。 这两个模块的含义是什么? 让我们举个小例子:
// custom-error.js 'use strict' function CustomError () {} CustomError.prototype = Object.create(Error.prototype) CustomError.prototype.constructor = CustomError module.exports = CustomError // module-a.js const CustomError = require('./custom-error') const err = new CustomError(...) module.exports = err // module-b.js const CustomError = require('./custom-error') const err = new CustomError(...) module.exports = err // dummy file to require those const CustomError = require('./custom-error') const errA = require('./module-a') const errB = require('./module-b')
首先, errA
和errB
都应该是instanceof CustomError
一个instanceof CustomError
:
console.log(errA instanceof CustomError) // yields true console.log(errB instanceof CustomError) // yields true
将在原型链中find的errA
和errB
的errA
属性应该有引用指向相同的函数对象CustomError
console.log(errA.constructor === errB.constructor) // yields true
让我们介绍一下过滤的catch例子:
const Promise = require('bluebird') Promise.resolve() .then(() => { throw errA }) .catch(CustomError, err => { console.log('instance of CustomError catched', err) throw errB }) .catch(CustomError, err => { console.log('instance of CustomError catched again', err) })
结果:
instance of CustomError catched [Error] instance of CustomError catched again [Error]
而最后一件事,当你说deep npm dependencies
时,你的意思是什么? 这个CustomError
事情是你的模块或第三方库? 第三方模块的事实,不应该改变任何东西。