簡體   English   中英

復雜的循環節點模塊依賴性拋出“TypeError:超級構造函數'繼承'必須有一個原型”

[英]Complex circular Node module dependency throwing “TypeError: The super constructor to 'inherits' must have a prototype”

我有一個復雜的Node SDK項目,它使用一些類繼承來嘗試和static-ify Javascript。 我正在使用Node的模塊緩存行為為SDK( Project類, ProjectClient的共享實例)創建類似單一的行為。 對於init,它看起來像這樣:

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 “singleton”時,這些工作正常。

我現在正在嘗試創建附加到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)

故障導致我這之中涉及到util.inherits(ProjectUser, ProjectEntity)User ,因為如果我注釋掉,我得到這個:

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模塊執行任何操作。 在該模塊上沒有導出任何內容,因此它只是一個空對象。 然后,該模塊上的任何錯誤源都將與該模塊中所依賴的任何導出對象相關。 因此,如果您需要在Entity使用init的對象,那么就會出現問題。

您可以在初始化依賴關系鏈之前導出一些方法/函數,這將使它們可用。 NodeJS文檔為例:

a.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');

b.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');

main.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是起點。 它需要a.js ,它會立即導出一個已done屬性,然后需要b.js b.js還出口一個done財產。 下一行需要a.js ,它不會再次加載a.js但返回到目前為止的導出屬性(包括done屬性)。 在這一點上, a是不完整的,但它設法給b足以繼續工作。 它的下一行(上b.js )將打印輸出特性(a.done,這是假的),然后重新導出屬性done設置為true。 我們回到a.jsrequire('b.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

這是一個例子,以防您想閱讀官方文檔。

是的,所以重點......你能做什么?

只要您實際上不需要這些依賴項,就可以在初始化依賴項循環之前導出一些內容。 例如,你可以:

a.js

exports.func = function(){ console.log('Hello world'); }
var b = require('./b.js');
console.log('a done');

b.js

var a = require('./a.js');
a.func(); //i'm still incomplete but i got func!
console.log('b done');

你不能:

a.js

b.func(); //b isn't even an object yet.
var b = require('./b.js');
console.log('a done');

b.js

exports.func = function(){ console.log('hello world'); }
var a = require('./a.js');
a.func();
console.log('b done');

但是,如果你的a.js模塊只導出函數,那么只要沒有在其他地方調用這些函數就沒有真正的問題:

a.js

exports.func = function(){ b.func(); }
var b = require('./b.js');
console.log('a done');

b.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模塊。 只要在加載依賴項時不使用導出的函數,就可以遵循此模式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM