使用 google 关闭创建事件

发布于 2025-01-01 09:01:42 字数 1043 浏览 0 评论 0原文

我想使用事件在谷歌闭包(GC)环境中的对象之间进行通信。

假设我有两个类 foobar.Bossfoobar.Employee。老板想知道员工什么时候煮了咖啡,以及咖啡是否不含咖啡因(他本周将不再喝咖啡因)。

GC 已经提供了一些类,它们似乎提供了执行此操作的方法:goog.events.Eventgoog.events.EventTarget

如果不知道更多,我认为它会像这样工作:

foobar.Employee.prototype.makeCoffee = function(isDecaf)
{        
    this.coffeeMaker.putCoffeeInMachine(isDecaf);
    this.coffeeMaker.start();
    var event = new goog.event.Event('COFFEE_ON', { isDecaf: isDecaf });
    goog.events.dispatchEvent(event);
}

foobar.Boss.prototype.addEmployee = function(employee)
{
    ...
    goog.events.listen(employee, 'COFFEE_ON', function(e)
    {
        if (e.target.isDecaf)
        {
            this.refillMug();
        }
    }, false, this);
    ...
}

这是正确的模式吗?我对 goog.events.EventTarget 类感到困惑——目标如何调度事件?难道目标没有发生什么事情吗?

这个问题很有帮助,但答案更直接将不胜感激。

I would like to use events to communicate between my objects in a google closure (GC) environment.

Suppose I have two classes foobar.Boss and foobar.Employee. The Boss wants to know when the Employee has made coffee, and whether or not that coffee is decaf (he's laying off the caffeine this week).

GC has made classes available that seem to provide the means to do this, goog.events.Event and goog.events.EventTarget.

Without knowing better, I'd think it would work like this:

foobar.Employee.prototype.makeCoffee = function(isDecaf)
{        
    this.coffeeMaker.putCoffeeInMachine(isDecaf);
    this.coffeeMaker.start();
    var event = new goog.event.Event('COFFEE_ON', { isDecaf: isDecaf });
    goog.events.dispatchEvent(event);
}

foobar.Boss.prototype.addEmployee = function(employee)
{
    ...
    goog.events.listen(employee, 'COFFEE_ON', function(e)
    {
        if (e.target.isDecaf)
        {
            this.refillMug();
        }
    }, false, this);
    ...
}

Is this a correct pattern? I am confused by the class goog.events.EventTarget -- how does a target dispatch events? Doesn't a target have things happen to it?

This question is helpful, but a more direct answer would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

妞丶爷亲个 2025-01-08 09:01:42

经过一段时间的研究,我现在的理解是,EventTarget 实际上扮演着双重角色,既是调度事件的实体,也是被监听的实体。因此,一种选择是让 Employee 继承 goog.events.EventTarget 但我走了一条不同的路线。

首先,我创建了一个新的事件类型,让老板知道咖啡是否不含咖啡因。

/**
 * @constructor
 * @extends {goog.events.Event}
 */
foobar.CoffeeEvent = function(isDecaf)
{
  goog.events.Event.call(this, 'COFFEE_ON');
  this.isDecaf = isDecaf;
};
goog.inherits(foobar.CoffeeEvent, goog.events.Event);

接下来,我创建了一个事件侦听器类型来调度这些事件。

/**
 * @constructor
 * @extends {goog.events.EventTarget} 
 */
foobar.CoffeeEventTarget = function()
{
  goog.events.EventTarget.call(this);
};
goog.inherits(foobar.CoffeeEventTarget, goog.events.EventTarget);

我将这种类型的对象添加到我的 Employee 中。

foobar.Employee = function()
{
  ...
  this.coffeeEvents = new foobar.CoffeeEventTarget();
  ...
}

当员工重新倒咖啡时:

foobar.Employee.prototype.makeCoffee = function(isDecaf)
{        
    this.coffeeMaker.putCoffeeInMachine(isDecaf);
    this.coffeeMaker.start();
    var event = new foobar.CoffeeEvent(isDecaf);
    this.coffeeEvents.dispatchEvent(event);
}

博斯曼先生会倾听。

foobar.Boss.prototype.addEmployee = function(employee)
{
    ...
    goog.events.listen(employee.coffeeEvents, 'COFFEE_ON', function(e)
    {
        if (e.isDecaf)
        {
            this.refillMug();
        }
    }, false, this);
    ...
}

请注意,这不会告诉我哪个员工重新倒了咖啡,因为事件目标将是 CoffeeEventTarget 的实例。如果您想要其中的所有Employee,我想您可以将其添加为成员字段。如果您同意从 goog.events.EventTarget 继承 Employee,那么您可以免费获得 Employee 作为目标。

Having looked at this for a while, my understanding is now that the EventTarget in fact plays a dual roll of being the entity that dispatches events and the entity that is listened to. So one option would be to have Employee inherit goog.events.EventTarget but I have gone a different route.

First I created a new event type that would let the Boss know if the coffee was decaf.

/**
 * @constructor
 * @extends {goog.events.Event}
 */
foobar.CoffeeEvent = function(isDecaf)
{
  goog.events.Event.call(this, 'COFFEE_ON');
  this.isDecaf = isDecaf;
};
goog.inherits(foobar.CoffeeEvent, goog.events.Event);

Next I created an event listener type to dispatch these events.

/**
 * @constructor
 * @extends {goog.events.EventTarget} 
 */
foobar.CoffeeEventTarget = function()
{
  goog.events.EventTarget.call(this);
};
goog.inherits(foobar.CoffeeEventTarget, goog.events.EventTarget);

I added an object of this type to my Employee.

foobar.Employee = function()
{
  ...
  this.coffeeEvents = new foobar.CoffeeEventTarget();
  ...
}

When the employee refills the coffee:

foobar.Employee.prototype.makeCoffee = function(isDecaf)
{        
    this.coffeeMaker.putCoffeeInMachine(isDecaf);
    this.coffeeMaker.start();
    var event = new foobar.CoffeeEvent(isDecaf);
    this.coffeeEvents.dispatchEvent(event);
}

Mr. Bossman listens for this.

foobar.Boss.prototype.addEmployee = function(employee)
{
    ...
    goog.events.listen(employee.coffeeEvents, 'COFFEE_ON', function(e)
    {
        if (e.isDecaf)
        {
            this.refillMug();
        }
    }, false, this);
    ...
}

Note that this won't tell me which employee refilled the coffee, because the event target will an instance of CoffeeEventTarget. If you wanted all of Employee in there I suppose you could add it as a member field. If you were OK with inheriting to Employee from goog.events.EventTarget then you get Employee for free as the target.

七婞 2025-01-08 09:01:42

我对 EventTarget 的看法是这样的:

按钮是一个目标,您可以注册该目标,以便在发生点击事件时收到有关其点击事件的通知。因此,单击的“目标”是按钮(您瞄准按钮,然后单击它)。但是,当按钮被单击时,并不是鼠标告诉每个人该按钮已被单击 - 按钮本身会发送该消息。

触及@ben-flynn提出的关于为什么有人需要/想要子类化EventTarget的问题:

如果你想监听按键按下事件,你可能会关心关于按下了什么键。您知道按下了什么键的方法是查找由 KeyDownEventTarget 调度的事件对象上的 keyCode 字段。另一方面,ButtonEventTarget 调度不同的事件对象,即 ClickEvent,其中没有 keyCode 字段。总而言之,您将 EventTarget 子类化的原因是,无论谁正在侦听将由该目标分派的事件,都知道触发事件时将分派哪个事件对象。

The way I think of EventTarget is this:

A button is a target, which you can register to be notified about its click event whenever one takes place. Thus, the "target" of a click is the button (you aim at the button, then click on it). But when the button gets clicked, it's not the mouse that tells everyone that the button was clicked - the button itself dispatches that message.

To touch on the question brought up by @ben-flynn about why would someone need/want to subclass EventTarget:

If you want to listen for key down events, you probably care about what key was pressed. The way you'd know what key was pressed is by looking up the keyCode field on the event object that is dispatched by the KeyDownEventTarget. On the other hand, a ButtonEventTarget dispatches a different event object, namely a ClickEvent, which does not have a keyCode field in it. So to summarize, the reason you'd subclass EventTarget is so whoever is listening for events that will be dispatched by that target know what event object will be dispatched when the event is triggered.

娇俏 2025-01-08 09:01:42

我会这样做...

让我们设置一个咖啡类型。如果我们要更进一步,我们可以有一个基本的 Coffee 类,然后用 DecafCoffee 类对其进行子类化。但让事情变得简单。

foobar.Coffee.js

/**
 * @fileoverview Coffee class
 */

goog.provide('foobar.Coffee');

/**
 * @constructor
 */
foobar.Coffee = function(){
   //...
};

我们的 Employee 类必须实现 goog.events.EventTarget 才能分派事件。您一定不要忘记使用 goog.basegoog.events.EventTarget.call 调用父构造函数,因为这将设置类所需的内部变量。

foobar.Employee.js

/**
 * @fileoverview Implements the Employee class
 */

goog.provide('foobar.Employee');
goog.require('goog.events.EventTarget');
goog.require('foobar.Coffee');

/**
 * @constructor
 */
foobar.Employee = function(){
    // Calls the parent class (goog.events.EventTarget)
    goog.base(this);
};
goog.inherits(foobar.Employee, goog.events.EventTarget);

/**
 * Make a coffee
 */
foobar.Employee.prototype.makeCoffee = function(){
    // Determine what coffee type to make ...
    // Create the coffee
    var coffee = new foobar.Coffee();
    this.dispatchEvent({
        type: "decaf_coffee",
        target: coffee
    });
};

boss 类不需要做任何特殊的事情,因为它不会调度事件。它只需要一个我们可以调用的#drinkCoffee() 方法。

foobar.Boss.js

/**
 * @fileoverview Implements the Boss class
 */

goog.provide('foobar.Boss');

/**
 * @constructor
 */
foobar.Boss = function(){
   //...
};

/**
 * Make this boss drink coffee
 * @param {foobar.Coffee} coffee The coffee to drink
 */
foobar.Boss.prototype.drinkCoffee = function(coffee){
    //....
};

这是您将运行的主要 JavaScript 代码,您可以将其放置在任何您喜欢的位置,例如内联在浏览器中或其自己的脚本中。

ma​​in.js

goog.require('foobar.Boss');
goog.require('foobar.Employee');
goog.require('goog.events');

// Jane is the boss of Sam, but we will use lower case as I typically 
// only capitalise the first letter to indicate a constructor.
var jane = new Boss();
var sam = new Employee();

// Set up event listening
goog.events.listen(sam, "decaf_coffee", function(e){
    var coffee = e.target;
    // We've got the decaf coffee Sam made, now Jane can enjoy drinking it
    jane.drinkCoffee(coffee);
}, false, this);

// Tell Sam to make a coffee
sam.makeCoffee();

Here's how I would do it...

Let's set up a coffee type. If we were to take this further we could have a base Coffee class and then sub class it with a DecafCoffee class. But lets keep things simple.

foobar.Coffee.js

/**
 * @fileoverview Coffee class
 */

goog.provide('foobar.Coffee');

/**
 * @constructor
 */
foobar.Coffee = function(){
   //...
};

Our Employee class must implement goog.events.EventTarget to be able to dispatch events. You mustn't forget to call the parent constructor with goog.base or goog.events.EventTarget.call either as this will setup internal variables the class needs.

foobar.Employee.js

/**
 * @fileoverview Implements the Employee class
 */

goog.provide('foobar.Employee');
goog.require('goog.events.EventTarget');
goog.require('foobar.Coffee');

/**
 * @constructor
 */
foobar.Employee = function(){
    // Calls the parent class (goog.events.EventTarget)
    goog.base(this);
};
goog.inherits(foobar.Employee, goog.events.EventTarget);

/**
 * Make a coffee
 */
foobar.Employee.prototype.makeCoffee = function(){
    // Determine what coffee type to make ...
    // Create the coffee
    var coffee = new foobar.Coffee();
    this.dispatchEvent({
        type: "decaf_coffee",
        target: coffee
    });
};

The boss class doesn't need to do anything special as it won't be dispatching events. It just needs a #drinkCoffee() method we can call.

foobar.Boss.js

/**
 * @fileoverview Implements the Boss class
 */

goog.provide('foobar.Boss');

/**
 * @constructor
 */
foobar.Boss = function(){
   //...
};

/**
 * Make this boss drink coffee
 * @param {foobar.Coffee} coffee The coffee to drink
 */
foobar.Boss.prototype.drinkCoffee = function(coffee){
    //....
};

This is the main JavaScript code which you'll be running, you can put wherever you like, e.g. inline in the browser or in its own script.

main.js

goog.require('foobar.Boss');
goog.require('foobar.Employee');
goog.require('goog.events');

// Jane is the boss of Sam, but we will use lower case as I typically 
// only capitalise the first letter to indicate a constructor.
var jane = new Boss();
var sam = new Employee();

// Set up event listening
goog.events.listen(sam, "decaf_coffee", function(e){
    var coffee = e.target;
    // We've got the decaf coffee Sam made, now Jane can enjoy drinking it
    jane.drinkCoffee(coffee);
}, false, this);

// Tell Sam to make a coffee
sam.makeCoffee();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文