参数 e(事件)到底是什么,为什么将它传递给 JavaScript 函数?

IT技术 javascript events dom-events
2021-01-31 01:44:48

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

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

我一直接受事实就是这样,但现在我有一些问题(这让我很困惑):

  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;
        }
    };
    
5个回答

e缩写event

创建事件的最简单方法是单击页面上的某处。

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

现在,事件一直在发生,但是您对发生的所有事件并不感兴趣。当你正在感兴趣然而,在一些情况下,当你添加一个事件监听器,你知道会创建活动[1]的元素。例如,您想知道用户何时单击“订阅”按钮,并且您想在此事件发生时执行某些操作

为了对此事件做一些事情,您将事件处理程序绑定到您感兴趣的按钮。将处理程序绑定到元素的方法是执行element.addEventListener(eventName, handler)

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

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

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

希望有所帮助。

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

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

[1] 这并不完全正确,但更容易理解。更正确的说法是“向您知道将有事件流过的元素添加一个事件侦听器”。请参阅了解更多信息

e您所询问的参数是一个Event对象,它表示导致您的函数被执行的正在触发的事件。e并不是必须的,您可以将其命名为任何您想要的名称,就像所有其他函数参数一样。

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

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

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

var e = new Event();
callbackFunction(e);

这就是Event对象的e来源。

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

如果您没有e参数,该函数将不会停止工作但是如果您需要访问有关导致您的函数执行的事件的一些详细信息,您将需要e参数来获取它们。

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

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

var event;

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

console.log(event); // => undefined

唯一可行的方法是使用该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

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


浏览器中的每个节点都是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));
    }
  }
}

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

请注意,对于每个 distinct eventType,都有一个不同的数组。该数组可以listener为同一个eventType.


fire由浏览器调用以响应用户交互。浏览器知道进行了何种交互以及在哪个节点上进行了交互。它使用该知识fire在适当的节点上调用适当的参数,即eventTypeeventProperties

fire循环遍历与特定 eventType 关联的数组。遍历数组,它listener在传递eventProperties数组时调用数组中的每个函数

这就是listener仅使用特定 eventType 注册函数被调用一次的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

用户点击按钮后,浏览器调用fire按钮,将“click”作为 aneventType和持有eventProperties. 这会导致调用listener“click”下的所有注册函数eventType

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


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

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

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

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

  1. 这就是 JS 的工作方式,您在每个事件回调中都会获得事件对象。它包含有关该事件的大量信息。
  2. 如果你不通过它,函数不会停止工作,它是可选的。继续并 console.log 事件 (e) 并查看事件对象及其属性。当你看到它有什么时会更清楚。
  3. 您可以通过存储它在匿名函数之外使用它,例如:

    var myEvent;
    
    element.onkeypress = function(e) {
        myEvent = e;
        if(e.keyCode) {
            element.keyCode = e.keyCode;
        } else {
            element.keyCode = e.charCode;
        }
    };
    
    console.log(myEvent);
    

    但是您应该知道事件对象仅与发生的特定事件相关,并且考虑到您应该决定是否真的需要这样做。