JS模块化开发:如何让dynamicListeners模块访问主文件getUserInput函数
问题解答
需求可行性
完全可以实现,你遇到的问题本质是CommonJS规范下的循环引用加载顺序错误。
问题根源
你当前的代码执行顺序是:
- index.js 先执行
require('./dynamicListeners.js')加载子模块 - dynamicListeners.js 执行
require('./index.js'),此时index.js还没执行到module.exports = todoList的步骤,拿到的是一个空的导出对象 - index.js 继续执行,才定义todoList并完成导出,但子模块里之前拿到的空对象不会自动更新,导致调用
todoList.getUserInput时报错
最优实现方案
方案1:调整index.js的代码顺序(改动最小)
只需要把todoList的定义、导出逻辑移到加载dynamicListeners之前即可,修改后的index.js代码如下:
// 第一步:先定义主模块 const todoList = (() => { const init = function() { } const createNewItem = function(title, description, dueDate, priority, projectName) { let newItem = new todoItem(title, description, dueDate, priority, projectName); console.log(newItem); } const getUserInput = function() { let title = document.getElementById('titleBox').value; let description = document.getElementById('descripBox').value; let dueDate = document.getElementById('dateBox').value; let priority = document.getElementById('priorityBox'); let projectName = 'Default'; //创建新的待办项 todoList.createNewItem(title, description, dueDate, priority, projectName); } return { init, createNewItem, getUserInput } })(); // 第二步:先完成导出,再加载其他依赖 module.exports = todoList; // 第三步:加载外部模块 const dom = require('./dom.js'); const staticListeners = require('./staticListeners.js'); const dynamicListeners = require('./dynamicListeners.js'); // 执行外部模块初始化 dom.init(); staticListeners.init(); todoList.init(); dynamicListeners.init();
注意:你原代码todoList的return里包含了未定义的
test方法,会直接报错,我已经在示例代码里移除,你可以根据需求自行补全。
该方案生效的原因是:CommonJS的require是同步执行的,先完成主模块的导出再加载子模块,子模块内require主模块时就能拿到完整的todoList实例,直接调用getUserInput即可正常运行。
方案2:移除循环依赖(更符合低耦合设计规范)
如果你不想出现循环引用的情况,可以将todoList实例或需要的方法作为参数传递给dynamicListeners的init方法:
- 修改dynamicListeners.js,删除对index.js的引用,修改init方法接收传入的方法:
//加载dom模块 const dom = require('./dom.js'); const dynamicListeners = (() => { // 新增参数接收传入的getUserInput方法 const init = function(getUserInputFn) { this.getUserInput = getUserInputFn; console.log('This is the dynamic listeners init'); this.eventDelegation(); } const eventDelegation = function() { const that = this; document.getElementById('content').addEventListener("click", function(e){ let targetId = e.target.id; console.log('Ya clicked: ' + targetId); if (targetId === 'saveButton') { console.log('UR in the IF...'); // 调用传入的方法 that.getUserInput(); } }) } return { init, eventDelegation } })(); module.exports = dynamicListeners;
- 修改index.js里的dynamicListeners初始化调用:
// 把getUserInput方法作为参数传入 dynamicListeners.init(todoList.getUserInput);
这个方案完全消除了两个模块的循环依赖,代码可维护性更高。
内容的提问来源于stack exchange,提问作者ATEATEEFFEEE
相关产品推荐
相关产品推荐

