在由深度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。

  1. 检查构造函数名称。 Pro:简单,支持良好。 Con:最好选一个相当独特的名字来避免误报,并忘记对它进行分类。

  2. 检查对象的属性(例如同时具有“foo”和“bar”和“foo”是一个函数)。 临:大多是防呆的。 缺点:易碎:如果您重构自定义错误类,则此检查可能会随机中断,而且相对昂贵。

  3. (推荐)添加属性/方法。 这是一些库(例如,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 CustomErrormodule-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') 

首先, errAerrB都应该是instanceof CustomError一个instanceof CustomError

 console.log(errA instanceof CustomError) // yields true console.log(errB instanceof CustomError) // yields true 

将在原型链中find的errAerrBerrA属性应该有引用指向相同的函数对象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事情是你的模块或第三方库? 第三方模块的事实,不应该改变任何东西。