使用具有多个模块的模块模式,一个模块中的事件监听器如何使用来自另一个模块的回调?

Posted

技术标签:

【中文标题】使用具有多个模块的模块模式,一个模块中的事件监听器如何使用来自另一个模块的回调?【英文标题】:Using the module pattern with multiple modules, how can an event listener in one module use a callback from another module? 【发布时间】:2021-11-02 04:47:05 【问题描述】:

例如

const Foo = (function () 
   const something = [];
   const method1 = function()
      bar.addEventListener("click", method2); //how can I access this method from Foo2??
    ;
  return method1;
)();

const Foo2 = (function () 
    const method1 = Foo(???); //the example ive found that was remotely close
    const somethingElse = 10;
    const method2 = function()
       //do something
    ;
   return method2;
)();

在一个示例中,我发现他们使用了对象解构并将其设置为等于我想从中继承该特定函数的另一个模块。我试图实现这个,但它告诉我Foo 不是一个函数,或者我试图在没有初始化的情况下访问它。

在他们的示例中,他们在Foo 的括号中有一个变量,但是将其应用于我的项目 idk 括号中的内容,我尝试的所有内容都是错误的,甚至是空括号。此外,即使这确实有效,我也不知道在事件侦听器中的回调函数名称前面放什么。我试过bar.addEventListener("click", Foo2.method2);bar.addEventListener("click", Foo2.method2());

我看到这个问题以不同的方式提出了几个不同的答案,但老实说,这些解释只是超出了我的理解水平。对象解构对我来说最有意义,但它仍然不起作用,所以我不知道该怎么办。

我了解原型继承并且能够说Foo.prototype.someFunction 能够使用Foo 中的方法,但是实现此功能的“工厂函数/模块模式”等价物是什么?

不仅仅是事件,这两个模块如何相互连接?是语法错误,还是不可能?我只是想举个例子……某事。任务要求我们使用工厂函数和模块模式,我找不到任何资源,我可以找到简单的如何将常规函数转换为模块的资源,没有关于一旦你拥有多个模块后如何使用它们的资源不管什么原因。

【问题讨论】:

【参考方案1】:

解释为什么这不起作用比解释你应该做什么更容易,因为老实说这是一种奇怪的方法。

Foo 中的函数会立即被调用。分配给Foo 的值不是函数——它是函数的返回值,它是一个具有method1 属性的对象。

Foo2 内部,您可以使用const method1 = Foo; 访问变量Foo 的值。但是您不能在Foo 中访问Foo2,因为该函数被立即 调用,这意味着您正在尝试在定义之前访问Foo2。您不能简单地重新排序代码,因为您在 FooFoo2 之间存在循环依赖关系。

简而言之,使用 IIFE 无法做到这一点


所以不要立即调用你的函数。 Foo 可以是一个工厂,它接受一些参数并返回一个带有method1 的对象,Foo2 也是如此

如果您这样做,那么您可以拥有多个不同的 foo 对象实例。例如,const a = Foo2(5); const b = Foo2(10);。在不知道实际目标的情况下,我很难知道设计它的最佳方式。

如果您需要这种循环行为,其中 1 和 2 相互引用,那么这很难。您可能需要/希望您的 foo 工厂之一将另一个工厂的实例作为其参数之一。您可能需要/想要使用函数的 this 值。这将是一团糟。

如果是单向关系,那就容易多了。

这里我们创建一个Foo2 实例并将其传递给Foo

const bar = document.getElementById('bar');

// takes a Foo2 instance as an argument
const Foo = function (foo2Instance) 
    const something = [];
    const method1 = function() 
        bar.addEventListener("click", foo2Instance.method2);
    ;
    return method1;


// takes a number as an argument
const Foo2 = function (somethingElse) 
    const method2 = function() 
        alert(somethingElse);
    ;
    return method2;


const myFoo2 = Foo2(10);
const myFoo = Foo(myFoo2);
myFoo.method1();
<body>
  <div id="bar">Click Me</div>
</body>

这里Foo负责创建自己的内部Foo2实例。计数器“A”和“B”是完全分开的,单击一个不会增加另一个。这是因为每个 Foo 实例都有自己的 Foo2 实例。

const Foo = function (counterId) 
    const bar = document.getElementById(counterId);
    const foo2Instance = Foo2();
    const method1 = function() 
        bar.addEventListener("click", foo2Instance.method2);
    ;
    return method1;


const Foo2 = function () 
    let count = 0
    const method2 = function() 
       count++;
       console.log(`count is $count`);
    ;
    return method2;


const counterA = Foo("a");
counterA.method1();
const counterB = Foo("b");
counterB.method1();
<body>
  <div id="a">Counter A</div>
  <div id="b">Counter B</div>
</body>

【讨论】:

以上是关于使用具有多个模块的模块模式,一个模块中的事件监听器如何使用来自另一个模块的回调?的主要内容,如果未能解决你的问题,请参考以下文章

使用模块模式的变体附加javascript事件的问题

vue,在模块中动态添加dom节点,并监听

简单剖析Node中的事件监听机制

Node.js进击基础一(5-11事件模块)

node模块之events模块

laravel进阶系列--通过事件和事件监听实现服务解耦