你能让我轻易理解动态,抽象的事件对象吗?

时间:2009-01-22 22:40:12

标签: javascript event-driven

我使用MFC为GUI按钮编写了C ++事件驱动的应用程序,我使用像onmousedown这样的HTML事件来触发网页中的一些Javascript。当您使用界面并且事件是硬编码时,事件驱动编程的想法很直观。

我知道如何在C中使用函数指针,我看到Windows如何使用它们来运行事件循环。我可以编写代码来动态调用不同的函数。

我的问题是,从编译时移到运行时。我在这里谈论任何语言,但如果您需要一种语言,请选择Javascript或PHP,因为我最近使用它们。我完全没有掌握如何使用自己的事件对象来完成任务。这不是我得到的概念。由于我不使用它们,我不知道它们的实际用途可能是什么。

例如,我想如果我想制作一个自定义的回合制游戏,那么我可能会使用事件对象来表示某些游戏片段能力的影响,而这种能力只需要“发生”。

有人可以简单地使用自定义事件吗?或者有用或实用的情况?它在很大程度上取决于语言和环境以及如何处理事件?一个Javascript答案会很好,但我读了很多语言。

对不起,我只是缺乏这方面的东西,需要一些实用,先进(中级?)的见解。它就像是C中的指针。我“得到”指针以及它们是你的朋友。但有一段时间我没有,而我认识的许多人仍然没有。一旦你得到它就很简单,我就是不会那样获得自定义的动态事件。

6 个答案:

答案 0 :(得分:5)

当我们谈论面向事件的编程时,我们通常会讨论observer design pattern的一个或多个实现。观察者设计模式的一个目标是在对象之间实现loose coupling

如果没有一个很好的例子,这可能并不意味着什么,而且肯定有很多好的例子;我怀疑我的将是他们中最好的,但我会对它进行打击。想象一下两个物体。一个物体想要知道什么时候发生了与另一个物体发生的事情,所以它本身可以做一些事情 - 也许家里的狗,罗孚,当他下班回家时想要在门口迎接爸爸。您可以通过两种方式对该方案进行编程,对吧?

  • 确保爸爸有一个对罗孚的引用,当他回家时,打电话给罗孚的greetDatAtTheDoor()方法,或者

  • 给罗孚一个参考爸爸, 听爸爸的onArriveHome活动, 当它发射时,请打电话 内部greetDadAtTheDoor()。

从表面上看,两者之间似乎没有太大区别,但实际上,爸爸已经将罗孚的一些实施方式烧成了他;如果罗孚的实施由于某种原因不得不改变,我们必须在两个地方做出改变:一次是在罗孚,一次是在爸爸。也许并不是一件大事,但仍然不理想。

现在想象妈妈也想和爸爸打招呼。那只猫,Bigglesworth先生,他不太喜欢爸爸,想要确保他不在身边,所以他宁愿出门。一个邻居乔想知道爸爸什么时候回家,所以他可以告诉他爸爸欠他的二十块钱。我们如何解释所有这些情景,以及其他不可避免的情况?放置对妈妈的greetHusband()方法的引用,cat的getOutNow()方法,狗的greetDadAtTheDoor()方法和Joe的goGetMyMoney()方法进入爸爸的类定义会让爸爸快速搞砸 - 并且没有充分的理由,因为所有爸爸真的需要做,自己,回家。妈妈,狗,猫和邻居只是希望在发生这种情况时得到通知,因此他们可以做任何内部实施所需的事情。

语言以不同的方式处理这些东西的细节,但正如你将看到开始使用Google搜索时,模式通常涉及在事件“调度程序”上有一个数组或类似数组的结构(在此案例,爸爸 - 即,其他人都感兴趣的对象),“订阅者”(例如,妈妈,猫,流浪者和乔)都通过在调度员上调用公开暴露的方法并传入来“注册”引用自己 - 引用最终,以某种形式,在爸爸的“订阅者”数组中。然后,当爸爸回家时,他“派遣”一个活动 - “我回家了!”事件,比如说 - 这实际上是一个循环遍历每个订阅者的函数,并使用他们自己的一些可公开访问的方法调用它们 - 只有它是一个名字爸爸不知道的方法,不必知道,因为听众在他/她/它通过时提供了它。

由于这些天我碰巧主要编写ActionScript代码,这就是它在我的世界中的样子 - 比如,从我的妈妈班级中宣布:

var dad:Dad = new Dad();
dad.addEventListener(DadEvent.ARRIVED_HOME, greetHusbandAtDoor);

private function greetHusbandAtDoor(event:DadEvent):void
{
   // Go greet my husband
}

在爸爸,那么,当我回到家时,我所要做的就是:

dispatchEvent(new DadEvent(DadEvent.ARRIVED_HOME));

...并且因为Flash为我处理事件调度和通知细节(同样,每个人都做了一点不同,但在内部,Flash遵循我描述的概念模型),我的爸爸回家了,每个家庭成员做了自动注册的事情。

希望这能解释一下 - 事件思维是什么样的,松散耦合意味着什么,它为什么重要,等等。祝你好运!

答案 1 :(得分:2)

在编译的语言中,您可以编写自己的事件循环。在运行时语言中,它已经由主机环境实现,并且程序员只获得事件系统中的抽象接口。你永远不会看到事件循环。

使用事件构建功能有两个方面。第一个是定义事件触发的条件。在浏览器的javascript中,没有一个“mousedown”事件。事实上,页面上的每个元素都有一个。在这种情况下,它们中的任何一个将触发的条件基于鼠标光标的位置,以及鼠标按钮是否刚刚从向上状态切换到向下状态。这种情况可能会导致多个事件触发。 (在浏览器中,有一个叫做“冒泡”的东西与此有关。但这不在这里。)

另一个方面是事件处理程序。无论是否存在处理程序,都会发生事件。提供处理程序取决于您。在javascript中,函数是第一类值。它们在运行时定义,而不是在编译时定义 - 因此不需要指针或跳转表。您在运行时创建一个新函数,并将其分配给特定事件触发时主机环境查找的特殊属性。

所以在堆栈溢出时,每个向下箭头的“onclick”事件都会有一个事件处理程序,它会将箭头变为红色,减少数字,检查其他变量并有条件地显示通知。然后当处理程序返回时 - 它将线程的控制权返回给浏览器,并且hallelujah用户可以再次与浏览器交互。 (处理事件时所有交互都会停止,因此您最好快速完成)。这是使用jquery库的示例。

jQuery("a .downarrow")
.click(function(e){ e.target.style.color="red" /* ... do other things */ });

或在原始javascript(版本1.6)中,它可能是

Array.prototype.slice.apply(document.getElementsByTagName("a"))
.filter(function(o){ return !!(/downarrow/).exec(o.className)})
.forEach(function(o){ 
    o.onclick= function(e){ 
        e.target.style.color="red" /* ...do other things * / 
    }
 });

真的很简单。你会做这样的事情的主要原因是它允许异步交互。 gui应用程序不会一步一步地直线前进。它必须动态响应用户的输入。事件是一种伪造多线程应用程序外观的方法。它可以让用户看到许多事情同时发生而不会互相干扰。

您可以使用库来定义自定义事件。这可能会编码某些特定于域的事件。例如:你有一个国际象棋游戏,正在考虑下一步行动。搜索移动的过程耗尽时间。国际象棋游戏可以发射“onComputerMove”事件。您可以使用捕获移动规范的函数来处理该事件,并更新棋盘的可视化表示,并为用户弹出消息,然后退出。然后,当玩家移动时,你可以发起一个“onPlayerMove”事件,这可以做同样的事情。

答案 2 :(得分:1)

关于事件最奇妙的是减少两个模块或类之间的双向显式耦合。

所以说我有两个班:宝贝和妈妈


没有事件,我粗略地看到两种方法允许妈妈给宝宝喂奶:

  • 妈妈每隔半小时拨打一次婴儿baby.pokeBelly()方法,知道你是否需要拨打baby.fillWith(milk)
    问题是,妈妈的线程必须在婴儿进入一个循环后整天等待
  • 宝贝知道其相关的妈咪并拨打mommy.feed(me)方法,然后拨打baby.fillWith(milk)
    那么问题就是要求一个简单的婴儿让正确的妈妈填饱肚子 婴儿不这样做,因为他们应该保持简单。

通过事件,您可以将Mommy.OnBabyCries(baby)绑定到其宝贝的baby.Cry事件:

void Mommy.OnBabyCries(baby) {
    baby.fillWith(milk)
}

在此之后,如果宝宝想吃东西,它所要做的只是提高它的哭泣事件。

逻辑保留在妈妈身上,甚至在任何保姆的后期,婴儿保持快乐,而不必担心。

答案 3 :(得分:0)

我不知道我是否完全理解你的问题但是一个带有事件的类就像一个带按钮的GUI。只要把它想象成一个同性恋......在每个有活动的课堂里都有一个带虚拟按钮的小人。他不知道按钮会做什么,但他知道何时按下它。现在想想一个与其他小人物相关的课程。那个人知道,当他听到按下按钮的消息时,他应该做点什么。

任何时候你想让第二个人知道第一个人所做的事情,你就可以在第一个班级和第二个班级之间连接交换机(订阅活动)。当第一个人按下按钮(发射事件)时,第二个人会做任何他知道他应该做的事情......

我不知道这是否有帮助,或者我只是在考虑我的程序中的小人物的酸性旅行......

答案 4 :(得分:0)

StackOverflow,当您投票时,您的声誉会下降,而您的向下箭头会变红。

通常,您编写一个onclick,更新其中的所有元素,并且每次页面布局更改时都不要忘记更改它。

相反,您可以声明onVoteDown事件,在onclick中触发并订阅此事件:

  • 您的声誉div
  • 您的箭头img
  • 将您的投票发送到服务器的XmlHTTPRequest

答案 5 :(得分:0)

我不完全确定你正在寻找什么样的答案,所以如果这不是什么关系,我会道歉。 ;)


自定义 ,是指 自定义操作 自定义触发器 ,或真正的 自定义活动

例如: 自定义操作 会响应预定义的事件(例如,鼠标单击), 自定义触发器 会通过脚本伪造鼠标,而 自定义事件 将是一个未被语言定义或无法随时使用的侦听器。< / p>

如果您正在寻找自定义活动,我无法真正帮助您。虽然,我认为在JavaScript中对它们的支持并不多。


定义操作 ...

事件通常是通过对象的预定义属性建立的,比如window.onload。默认情况下,它们都等于undefinednull。因此,要使用它们,您必须将它们设置为函数的值。

您可以使用“匿名”功能:

window.onload = function (eventObject) {
    /* ... */
};

或者将它们设置为函数引用(不同,但类似于指针):

function handleOnload(eventObject) {
    /* ... */
}

window.onload = handleOnload; /* note the lack of parenthesis */

触发事件时,将调用该函数。因此,在任一设置中,当页面完成加载时,您执行的代码将被执行而不是/* ... */

还有更多正式的方法可用于创建活动。当IE使用addEventListener时,W3C定义attachEventMore info

有很多参考资料可用于学习可用事件列表。这里有2个应该给你一个很好的基础:


浏览器通常处理事件的触发 - 对于浏览器事件(onload)或用户事件(onclick)。属性和功能是为了响应。

触发您自己的活动并不是最容易实现的事情。要完全定义Event对象需要一些工作 - varies between browsers

但是,如果您不需要Event对象,则只需调用该事件:

window.onload();