复杂的循环节点模块依赖抛出“类型错误:'继承'的超级构造函数必须有一个原型”
Complex circular Node module dependency throwing "TypeError: The super constructor to 'inherits' must have a prototype"
我有一个复杂的Node SDK项目,它使用一些类继承来尝试静态化Javascript。我正在使用 Node 的模块缓存行为为 SDK(Project
类,ProjectClient
的共享实例(创建类似单例的行为。要初始化,它看起来像这样:
var Project = require('./project'),
Project.init(params)
// Project is now an instance of ProjectClient
我也有一些用于数据的对象类型类:Entity
(标准解析的 JSON 有效负载对象(和User
(包含用户属性的特殊类型的实体(。
ProjectClient
类有几个方法允许发生 RESTful API 调用,例如 Project.GET()
,Project.PUT()
。这些在实例化Project
"单例"时工作得很好。
我现在正在尝试创建附加到Entity
的便利方法,这些方法将利用ProjectClient
的 RESTful 操作,例如 Entity.save()
, Entity.refresh()
.
当我尝试将Project
导入Entity
时:
var Project = require('../project')
我得到:
TypeError: The super constructor to `inherits` must have a prototype.
at Object.exports.inherits (util.js:756:11)
故障排除使我发现这与User
中的util.inherits(ProjectUser, ProjectEntity)
有关,因为如果我将其注释掉,我会得到这个:
Uncaught TypeError: ProjectEntity is not a function
inherits
是怎么回事?为什么它认为Entity
没有原型?我最好的猜测是这与我在其他模块中递归嵌套模块的事实有关(我知道很糟糕(,但我什至尝试过在各种类中做这样的事情,但无济于事:
module.exports = _.assign(module.exports, **ClassNameHere**)
下面是每个类的一些简化代码:
实体
var Project = require('../Project'),
_ = require('lodash')
var ProjectEntity = function(obj) {
var self = this
_.assign(self, obj)
Object.defineProperty(self, 'isUser', {
get: function() {
return (self.type.toLowerCase() === 'user')
}
})
return self
}
module.exports = ProjectEntity
用户(实体的子类(
var ProjectEntity = require('./entity'),
util = require('util'),
_ = require('lodash')
var ProjectUser = function(obj) {
if (!ok(obj).has('email') && !ok(obj).has('username')) {
// This is not a user entity
throw new Error('"email" or "username" property is required when initializing a ProjectUser object')
}
var self = this
_.assign(self, ProjectEntity.call(self, obj))
return self
}
util.inherits(ProjectUser, ProjectEntity)
module.exports = ProjectUser
项目("单例",但不是真的(
'use strict'
var ProjectClient = require('./lib/client')
var Project = {
init: function(options) {
var self = this
if (self.isInitialized) {
return self
}
Object.setPrototypeOf(Project, new ProjectClient(options))
ProjectClient.call(self)
self.isInitialized = true
}
}
module.exports = Project
客户
var ProjectUser = require('./user'),
_ = require('lodash')
var ProjectClient = function(options) {
var self = this
// some stuff happens here to check options and init with default values
return self
}
ProjectClient.prototype = {
GET: function() {
return function() {
// async GET request with callback
}
},
PUT: function() {
return function() {
// async PUT request with callback
}
}
}
module.exports = ProjectClient
因此,正如您正确推断的那样,循环依赖存在问题。您的Entity
模块需要Project
模块,该模块需要Client
模块,该模块需要Entity
模块的User
模块。
你可以做些什么,但这取决于你的起点。如果首先需要Project
模块,则它应该使用提供的代码,因为Entity
模块不会对Project
模块执行任何操作。该模块上没有导出任何内容,因此它只是一个空对象。再说一次,该模块上的任何错误源都将与该模块内依赖的任何导出对象相关。因此,如果您需要内部有init
的对象Entity
那么就会有问题。
您可以在初始化依赖链之前导出一些方法/函数,这将使它们在那时可用。以NodeJS
文档为例:
答.js
console.log('a starting');
exports.done = false;
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
乙.js
console.log('b starting');
exports.done = false;
var a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
主.js
console.log('main starting');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);
所以,main.js
是起点。它需要立即导出done
属性的a.js
,然后需要b.js
。 b.js
还会导出done
属性。下一行需要 a.js
它不会再次加载a.js
,但返回到目前为止导出的属性(包括 done
属性(。在这一点上,a
不完整,但它已经设法给了b
足够的时间来继续工作。下一行(在b.js
上(将打印导出的属性(a.done,这是假的(,然后将导出的属性done
重置为true。我们又回到了require('b.js')
线上的a.js
。 b.js
现在已完全加载,其余部分很容易解释。
输出为:
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true
这是示例,以防万一您想阅读官方文档。
对,所以点是...你能做什么?
可以在初始化依赖周期之前导出一些内容,只要您实际上不需要这些依赖项即可。例如,您可以:
答.js
exports.func = function(){ console.log('Hello world'); }
var b = require('./b.js');
console.log('a done');
乙.js
var a = require('./a.js');
a.func(); //i'm still incomplete but i got func!
console.log('b done');
你不能:
答.js
b.func(); //b isn't even an object yet.
var b = require('./b.js');
console.log('a done');
乙.js
exports.func = function(){ console.log('hello world'); }
var a = require('./a.js');
a.func();
console.log('b done');
但是,如果您的a.js
模块仅导出函数,那么只要这些函数不在其他地方调用,就没有真正的问题:
答.js
exports.func = function(){ b.func(); }
var b = require('./b.js');
console.log('a done');
乙.js
exports.func = function(){ console.log('hello world'); }
var a = require('./a.js');
console.log('b done');
您正在导出一个使用 b
的函数,该函数不需要立即知道b
,只需在调用它时才知道。因此,两个模块都已正确加载。如果您只是导出函数,那么之后声明依赖项没有问题。
因此,您可以从主要点开始要求a.js
,func
将正常工作,因为现在b
参考点到完整的b.js
模块。只要在加载依赖项时不使用导出的函数,就可以遵循此模式。
- JavaScript对象不是从原型链继承的
- 如何使用原型继承编写一个整洁灵活的复杂javascript应用程序
- $emit,$broadcast,原型继承
- Javascript:继承原型而不重新定义构造函数
- 原型继承未按预期工作
- JavaScript中的原型继承.我可以称之为“超级”等价物吗?
- 为什么函数对象的实例没有继承函数原型属性
- 不创建父对象的原型继承
- Javascript基本继承与Crockford原型继承
- JavaScript-构造函数参数和原型继承
- 使用Object.create作为原型的原型继承将[Object]作为实例的原型
- javascript继承中正确的原型做作是什么
- 如何进行JavaScript原型继承(原型链)
- Javascript原型继承原型函数调用
- 对象不继承原型函数
- 从其他类继承原型方法,而不重写自己的原型方法
- JavaScript继承原型
- 继承原型
- Javascript继承/原型混淆
- 使用.call(this)继承原型