参数e(事件)究竟是什么以及为什么将它传递给JavaScript函数?

Lor*_*ill 32 javascript events javascript-events

好吧,当我学习JavaScript时,我读过的所有书籍和互联网文章都显示了将参数传递给e处理JavaScript事件的函数的代码,例如下面的代码块:

function myEvent(e) {
    var evtType = e.type
    alert(evtType)
    // displays click, or whatever the event type was
}
Run Code Online (Sandbox Code Playgroud)

我总是接受它的方式,但现在我有一些问题(这对我来说非常混乱):

  1. e是从哪里来的?当我查看整个JavaScript文件时,e似乎根本不存在.
  2. 为什么将此参数传递e给函数?如果我没有传递e给他们,功能是否会停止工作?
  3. 考虑下面的代码块.e传递给匿名内部函数的事件变量().假设我想在匿名函数之外使用事件对象(可能在行上方/下方的element.onkeypress行中).我怎样才能做到这一点?

    element.onkeypress = function(e) {
        if(e.keyCode) {
            element.keyCode = e.keyCode;
        } else {
            element.keyCode = e.charCode;
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)

Dim*_*nis 59

e是简称event

创建事件的最简单方法是单击页面上的某个位置.

单击时,将click触发事件.这event实际上是一个对象,其中包含有关刚刚发生的操作的信息.在此示例中,事件将具有诸如单击的坐标(event.screenX例如),您单击的元素(event.target)等信息.

现在,事件一直在发生,但是你对所发生的所有事件都不感兴趣.如果您兴趣,但有些情况下,当你添加一个事件监听器,你知道该元素将创建活动的[1].例如,您有兴趣了解用户何时单击"订阅"按钮,并且您希望在此事件发生时执行某些操作.

为了对这个事件做一些事情,你将事件处理程序绑定到你感兴趣的按钮.将处理程序绑定到元素的方法就是这样做element.addEventListener(eventName, handler).

eventName是一个字符串,它是您感兴趣的事件的名称,在这种情况下'click'(对于click事件).

处理程序只是一个在事件发生时执行某些操作(它已执行)的函数.默认情况下,处理程序函数在执行时传递event对象(在您感兴趣的事件/操作发生时创建)作为参数.

event处理函数定义为参数是可选的,但有时(大多数情况下),处理函数有助于了解发生的事件.当你定义它,这是e你在像你提到的那些功能见.请记住,event它只是一个常规的javascript对象,上面有很多属性.

希望有所帮助.

有关更多信息,请参阅创建和触发事件

至于你的第三个问题,现在你应该知道你不能这样做,因为e只有在事件发生时才存在.您可以拥有处理程序函数,该函数e在执行时可以访问该对象,并将其存储在某个全局变量中并对其进行处理.

[1]这不完全正确,但理解起来更简单.更正确的说法是"向你知道会让事件流经它的元素添加一个事件监听器".有关更多信息,请参阅


Arn*_*ane 9

e您询问的参数是一个Event对象,它表示被触发的事件导致您的函数被执行.它不是真的必须e,你可以像所有其他功能参数一样命名它.

  1. 这个e来自哪里?当我查看整个javascript文件时,e似乎根本不存在.

您将无法e在javascript文件中找到此变量,因为它根本不存在,而是来自执行回调函数的javascript引擎.

当你为某个事件(例如element.onkeypress = function(e) { ... })提供回调函数时,你给javascript引擎一个函数来在该事件触发时执行/调用,当它执行/调用你的回调函数时,它传递一个Event表示刚刚发生的事件的对象.Javascript可能会做这样的事情来调用你的回调函数:

var e = new Event();
callbackFunction(e);
Run Code Online (Sandbox Code Playgroud)

这就是Event对象e来自的地方.

  1. 为什么将此参数e传递给函数?如果我没有将e传递给它,该功能是否会停止工作?

如果您没有e参数,该功能将不会停止工作.但是,如果您需要访问导致执行函数的事件的一些细节,那么您将需要e参数来获取它们.

  1. 考虑下面的代码块,有一个事件变量(e)传递给匿名内部函数.假设我想在匿名函数之外使用事件对象(可能在element.onkeypress行上方/下方的行中),我该怎么做?

我不认为你可以这样做,即使你把它存储在回调函数范围之外的变量中.这是因为您声明它时不会立即执行您的函数,而只是在事件被触发时(例如,按下一个键,触发'keypress'事件).

var event;

element.onkeypress = function(e) {
    event = e;
    ...
};

console.log(event); // => undefined
Run Code Online (Sandbox Code Playgroud)

这可行的唯一方法是使用event变量的代码也会在以后执行,特别是在给定onkeypress执行的匿名函数之后 执行.所以下面的代码可以工作:

var event;

element.onkeypress = function(e) {
    event = e;
    ...
};

setTimeout(function() {
    console.log(event); // => the event object, if the `keypress` event
                        //    fired before `setTimeout` calls this function
}, 100000); // <= set to very large value so that it gets run way way later
Run Code Online (Sandbox Code Playgroud)


Rob*_*obG 5

当使用addEventListener添加侦听器时,传递给函数的第一个参数是一个 Event 对象,因此它将被分配给e参数(或为函数的第一个参数指定的任何名称)。


Har*_*uri 5

我会尽力用最抽象的方式来解释。真正的实现可能要复杂得多。因此,我将要使用的名称是假设的,但我希望它们确实有助于解释事物;)


浏览器中的每个节点都是类的实现 EventEmitter。此类维护一个events包含键:值eventType对(键)的对象:包含listener函数(值)的数组。

EventEmitter 类中定义的两个函数是addEventListenerfire

class EventEmitter {
  constructor(id) {
    this.events = {};
    this.id = id;
  }

  addEventListener(eventType, listener) {
    if (!this.events[eventType]) {
      this.events[eventType] = [];
    }

    this.events[eventType].push(listener);
  }

  fire(eventType, eventProperties) {
    if (this.events[eventType]) {
      this.events[eventType].forEach(listener => listener(eventProperties));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

addEventListener程序员使用它来注册他们想要的listener函数,以便在执行他们想要的eventType.

请注意,对于每个不同的eventType,都有一个不同的数组。该数组可以保存listener同一个 的多个函数eventType


fire由浏览器调用以响应用户交互。浏览器知道已经执行了什么样的交互以及在哪个节点上执行了交互。它使用该知识通过适当的参数(即和 )调用fire适当的节点。eventTypeeventProperties

fire循环遍历与特定事件类型关联的数组。遍历数组,它listener在传递给数组时调用数组内的每个函数eventProperties

这就是listener仅使用特定事件类型注册的函数在被fire调用后被调用的方式。


下面是演示。本次演示中有 3 位演员。程序员、浏览器和用户。

let button = document.getElementById("myButton"); // Done by the Programmer
let button = new EventEmitter("myButton"); // Done by the Browser somewhere in the background. 


button.addEventListener("click", () =>
  console.log("This is one of the listeners for the click event. But it DOES NOT need the event details.")
); // Done By the Programmer


button.addEventListener("click", e => {
  console.log(
    "This is another listener for the click event! However this DOES need the event details."
  );
  console.log(e);
}); // Done By the Programmer


//User clicks the button


button.fire("click", {
  type: "click",
  clientX: 47,
  clientY: 18,
  bubbles: true,
  manyOthers: "etc"
}); // Done By the Browser in the background
Run Code Online (Sandbox Code Playgroud)

用户单击按钮后,浏览器调用fire按钮,将“click”作为eventType和持有的对象传递eventProperties。这会导致调用listener“click”下所有注册的函数。eventType

正如您所看到的,浏览器总是着火eventProperties。作为程序员,您可能会也可能不会在您的listener函数中使用这些属性。


我发现在 stackoveflow 上有帮助的一些答案:

使用 addEventListener 注册的事件存储在哪里?

Javascript 事件处理程序存储在哪里?