В последнее время я работал с nodejs и до сих пор разбираюсь с системой модулей, поэтому извиняюсь, если это очевидный вопрос. Я хочу код примерно так, как показано ниже:
a.js (основной файл запускается с узлом)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var a = require("./a");
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
Кажется, моя проблема в том, что я не могу получить доступ к экземпляру ClassA из экземпляра ClassB.
Есть ли правильный / лучший способ структурировать модули для достижения того, что я хочу? Есть ли лучший способ поделиться переменными между модулями?
Ответы:
Хотя node.js допускает циклические
require
зависимости, как вы выяснили, это может быть довольно грязно, и вам, вероятно, лучше реструктурировать свой код, чтобы он не требовался. Может быть, создать третий класс, который использует два других, чтобы выполнить то, что вам нужно.источник
exports = {}
вверху кода, а затемexports = yourData
в конце кода. С этой практикой вы избежите почти всех ошибок от циклических зависимостей.Попробуйте установить свойства
module.exports
вместо полной замены. Например,module.exports.instance = new ClassA()
вa.js
,module.exports.ClassB = ClassB
вb.js
. Когда вы создаете циклические зависимости модуля, запрашиваемый модуль получает ссылку на неполноеmodule.exports
из требуемого модуля, к которому вы можете добавить другие свойства, но при установке целогоmodule.exports
вы фактически создаете новый объект, которого у запрашивающего модуля нет способ доступа.источник
module.exports
без его полной замены, чтобы позволить другим классам «конструировать» экземпляр класса?[РЕДАКТИРОВАТЬ] это не 2015, и большинство библиотек (т.е. экспресс) сделали обновления с лучшими шаблонами, поэтому циклические зависимости больше не нужны. Я рекомендую просто не использовать их .
Я знаю, что выкопал старый ответ здесь ... Проблема здесь в том, что module.exports определяется после того, как вам требуется ClassB. (что показывает ссылка JohnnyHK) Круговые зависимости прекрасно работают в Node, они просто определяются синхронно. При правильном использовании они фактически решают много общих проблем с узлами (например, доступ к express.js
app
из других файлов)Просто убедитесь, что ваш необходимый экспорт определен до вам потребуется файл с круговой зависимостью.
Это сломается:
Это будет работать:
Я постоянно использую этот шаблон для доступа к express.js
app
в других файлах:источник
app = express()
Иногда очень сложно ввести третий класс (как советует JohnnyHK), поэтому в дополнение к Ianzz: если вы хотите заменить module.exports, например, если вы создаете класс (например, файл b.js в В приведенном выше примере) это также возможно, просто убедитесь, что в файле, который запускает циклическое требование, оператор 'module.exports = ...' происходит перед оператором требования.
a.js (основной файл запускается с узлом)
b.js
источник
Решение состоит в том, чтобы «объявить вперед» ваш объект экспорта, прежде чем требовать какого-либо другого контроллера. Поэтому, если вы структурируете все свои модули, как это, и у вас не возникнет таких проблем:
источник
exports.foo = function() {...}
вместо этого. Определенно сделал свое дело. Спасибо!module.exports
по умолчанию уже является обычным объектом, поэтому ваша строка "предварительного объявления" является избыточной.Решение, которое требует минимальных изменений, расширяется
module.exports
а не переопределяет его.a.js - точка входа и модуль приложения, которые используют метод do из b.js *
b.js - модуль который использует метод do из a.js
Будет работать и производить:
Пока этот код не будет работать:
a.js
b.js
Вывод:
источник
underscore
, то ES6Object.assign()
может сделать ту же работу, что_.extend()
и в этом ответе.Как насчет ленивых, требующих только тогда, когда это необходимо? Итак, ваш b.js выглядит следующим образом
Конечно, хорошей практикой является размещение всех требуемых операторов в верхней части файла. Но бывают случаи, когда я прощаю себя за то, что выбрал что-то из другого, не связанного с этим модуля. Называйте это хаком, но иногда это лучше, чем вводить дополнительную зависимость или добавлять дополнительный модуль или добавлять новые структуры (EventEmitter и т. Д.)
источник
Другой метод, который, как я видел, делают люди, - это экспорт в первой строке и сохранение его как локальной переменной, например:
Я склонен использовать этот метод, знаете ли вы о его недостатках?
источник
module.exports.func1 =
,module.exports.func2 =
Вы можете легко решить эту проблему: просто экспортируйте свои данные, прежде чем требовать что-либо еще в модулях, где вы используете module.exports:
classA.js
classB.js
источник
Как и в ответах Lanzz и Setect, я использовал следующую схему:
В
Object.assign()
копирует член вexports
объект , который уже был дан к другим модулям.=
Назначение логически излишним, так как он просто установивmodule.exports
для себя, но я использую его , потому что это помогает мой IDE (WebStorm) признать , чтоfirstMember
это свойство этого модуля, так что «Go To -> Декларация» (Cmd-B) и другие инструменты будут работать из других файлов.Этот шаблон не очень хорош, поэтому я использую его только тогда, когда нужно решить проблему циклической зависимости.
источник
Вот быстрый обходной путь, который я нашел полным.
В файле «a.js»
В файле «b.js» напишите следующее
Таким образом, на следующей итерации классы цикла событий будут определены правильно, а операторы require будут работать как положено.
источник
На самом деле я в конечном итоге требует моей зависимости с
не красиво, но это работает. Это более понятно и честно, чем изменение b.js (например, только расширение модуля. Экспорт), который в остальном идеален как есть.
источник
Один из способов избежать этого - не требовать, чтобы один файл находился в другом, просто передайте его в качестве аргумента функции, которая вам когда-либо понадобится в другом файле. Таким образом, круговая зависимость никогда не возникнет.
источник