【问题标题】:What exactly is the parameter e (event) and why pass it to JavaScript functions?参数 e (event) 到底是什么,为什么要将它传递给 JavaScript 函数?
【发布时间】:2016-06-26 11:17:49
【问题描述】:

嗯,当我学习 JavaScript 时,我阅读的所有书籍和 Internet 文章都显示了将参数 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;
        }
    };
    

【问题讨论】:

    标签: javascript events dom-events


    【解决方案1】:

    eevent 的缩写

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

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

    现在,事件一直在发生,但是您对所有发生的事件并不感兴趣。但是,当您对某个事件感兴趣时,就是向您知道会创建事件的元素添加事件侦听器[1]。例如,您想知道用户何时点击“订阅”按钮,并且您想在此事件发生时做某事

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

    eventName 是一个字符串,它是您感兴趣的事件的名称,在本例中为'click'(用于click 事件)。

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

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

    希望有所帮助。

    更多信息请阅读Creating and Triggering Events

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

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

    【讨论】:

      【解决方案2】:

      您询问的参数e 是一个Event 对象,它 表示正在触发的导致您的函数执行的事件。它不一定是e,你可以像所有其他函数参数一样命名它。

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

      您将无法在 javascript 文件中找到此 e 变量,因为 它实际上根本不存在,而是来自执行的 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
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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


          浏览器中的每个节点都是EventEmitter 类的实现。此类维护一个对象 events,其中包含 key:valueeventType(键):一个包含 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 时被触发。

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


          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,将“点击”作为eventType 和持有eventProperties 的对象传递。这会导致调用“单击”eventType 下所有已注册的listener 函数。

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


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

          Where is an event registered with addEventListener stored?

          Where are Javascript event handlers stored?

          【讨论】:

            【解决方案5】:
            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);
              

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

            【讨论】:

              猜你喜欢
              • 2011-03-14
              • 1970-01-01
              • 2012-07-06
              • 1970-01-01
              • 2018-04-19
              • 1970-01-01
              • 1970-01-01
              • 2017-07-06
              • 1970-01-01
              相关资源
              最近更新 更多