参数 e(事件)到底是什么,为什么要将它传递给 JavaScript 函数?
What exactly is the parameter e (event) and why pass it to JavaScript functions?
嗯,当我学习 JavaScript 时,我阅读的所有书籍和互联网文章都显示代码将参数 e
传递给处理 JavaScript 事件的函数,例如代码块以下:
function myEvent(e) {
var evtType = e.type
alert(evtType)
// displays click, or whatever the event type was
}
我一直都这么认为,但现在我有一些问题(这让我很困惑):
- 这个
e
从哪里来的?当我查看整个 JavaScript 文件时,e
似乎根本不存在。
- 为什么要将此参数
e
传递给函数?如果我不将 e
传递给函数,函数会停止工作吗?
考虑下面的代码块。有一个事件变量 (e
) 传递给匿名内部函数。假设我想在匿名函数之外使用一个事件对象(可能在 above/below 行 element.onkeypress
行中)。我该怎么做?
element.onkeypress = function(e) {
if(e.keyCode) {
element.keyCode = e.keyCode;
} else {
element.keyCode = e.charCode;
}
};
当使用 addEventListener 添加侦听器时,传递给该函数的第一个参数是一个 Event 对象,因此它将被分配给 e 参数(或为函数的第一个参数指定的任何名称)。
- 这就是 JS 的工作原理,你在每个事件回调中获得事件对象。它包含很多关于事件的信息。
- 不通过则功能不会停止,可选。继续 console.log 事件 (e) 并查看事件对象及其属性。当你看到它有什么时,它会更清楚。
您可以通过存储它在该匿名函数之外使用它,例如:
var myEvent;
element.onkeypress = function(e) {
myEvent = e;
if(e.keyCode) {
element.keyCode = e.keyCode;
} else {
element.keyCode = e.charCode;
}
};
console.log(myEvent);
但您应该知道事件对象仅与发生的特定事件有关,考虑到您应该决定是否真的需要这样做。
你问的参数e
是一个Event
对象,它
代表被触发的事件,它导致你的函数被执行。它不一定是 e
,您可以像所有其他函数参数一样将其命名为任何您想要的名称。
- 这个e是哪里来的?当我查看整个 javascript 文件时,e
似乎根本不存在。
您将无法在 javascript 文件中找到此 e
变量,因为
它实际上根本不存在,但来自 javascript 引擎执行
你的回调函数。
当你为某些事件提供回调函数时
(例如 element.onkeypress = function(e) { ... }
),你给出了
javascript 引擎函数 execute/call 当该事件触发时,以及
它 executes/calls 你的回调函数 它传递一个 Event
对象
代表刚刚发生的事件。 Javascript 可能正在做某事
像这样调用你的回调函数:
var e = new Event();
callbackFunction(e);
这就是 Event
对象 e
的来源。
- 为什么要把这个参数e传给函数?该功能是否会停止工作,如果
我不传e给它?
如果没有e
参数,函数不会停止工作。
但是,如果您需要访问有关导致您的事件的一些详细信息
要执行的函数,您将需要 e
参数来获取它们。
- 考虑下面的代码块,有一个事件变量 (e) 传递给
匿名内部函数。假设我想在
匿名函数(可能在 above/below 行 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
e
是 event
的缩写
创建事件的最简单方法是单击页面上的某个位置。
单击时,会触发 click
事件。这个 event
实际上是一个包含有关刚刚发生的动作的信息的对象。在此示例中,事件将包含点击坐标(例如 event.screenX
)、您点击的元素(event.target
)等信息。
现在,事件一直在发生,但是您对发生的所有事件都不感兴趣。但是,当您 对某个事件感兴趣时,就是在您将事件侦听器添加到您知道会创建事件的元素时 [1]。例如,您有兴趣了解 用户何时单击 'Subscribe' 按钮 并且您想在该事件发生时 做某事 。
为了对此事件做一些事情,您将 事件处理程序 绑定到您感兴趣的按钮。将处理程序绑定到元素的方法是 element.addEventListener(eventName, handler)
.
eventName
是一个字符串,它是您感兴趣的事件的名称,在本例中为 'click'
(对于 click
事件)。
处理程序只是一个函数,它在事件发生时做一些事情(它被执行)。默认情况下,处理程序函数在执行时 传递给 event
对象 (当您感兴趣的 event/action 发生时创建)作为参数。
将 event
定义为处理函数的参数是可选的,但有时(大多数时候),处理函数了解发生的事件很有用。当你做定义它时这就是你在你提到的函数中看到的e
。请记住,event
只是一个普通的 javascript 对象,上面有很多属性。
希望对您有所帮助。
有关详细信息,请阅读 Creating and Triggering Events
关于你的第三个问题,现在你应该知道你不能那样做,因为e
只有在事件发生时才存在。您可以拥有处理函数,它在执行时可以访问 e
对象,将其存储在某个全局变量中并对其进行处理。
[1] 这不完全正确,但更容易理解。更正确的说法是"add an event listener to the element you know will have events flow through it"。有关详细信息,请参阅 this
我会尽量用最抽象的方式来解释。真正的实现可能要复杂得多。因此,我将要使用的名称是假设的,但我希望它们确实有助于解释事物;)
浏览器中的每个节点都是 EventEmitter
class 的实现。 class 维护一个对象 events
,其中包含 key:value 对 eventType
(键):一个包含 listener
函数的数组(价值)。
EventEmitterclass中定义的两个函数是addEventListener
和fire
。
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
,并使用适当的参数 eventType
和 eventProperties
。
fire
循环遍历与特定 eventType 关联的数组。遍历数组,它调用数组中的每个 listener
函数,同时将 eventProperties
传递给它。
这就是 listener
函数的调用方式,仅使用特定的 eventType 注册,一旦 fire
被调用。
下面是演示。此演示中有 3 个 Actor。程序员、浏览器和用户。
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" 作为 eventType
传递,对象持有 eventProperties
。这会导致调用 "click" eventType
下所有已注册的 listener
函数。
如您所见,浏览器总是 使eventProperties
着火。作为一名程序员,您可能会也可能不会在 listener
函数中使用这些属性。
我发现在 stackoveflow 上有帮助的一些答案:
Where is an event registered with addEventListener stored?
Where are Javascript event handlers stored?
嗯,当我学习 JavaScript 时,我阅读的所有书籍和互联网文章都显示代码将参数 e
传递给处理 JavaScript 事件的函数,例如代码块以下:
function myEvent(e) {
var evtType = e.type
alert(evtType)
// displays click, or whatever the event type was
}
我一直都这么认为,但现在我有一些问题(这让我很困惑):
- 这个
e
从哪里来的?当我查看整个 JavaScript 文件时,e
似乎根本不存在。 - 为什么要将此参数
e
传递给函数?如果我不将e
传递给函数,函数会停止工作吗? 考虑下面的代码块。有一个事件变量 (
e
) 传递给匿名内部函数。假设我想在匿名函数之外使用一个事件对象(可能在 above/below 行element.onkeypress
行中)。我该怎么做?element.onkeypress = function(e) { if(e.keyCode) { element.keyCode = e.keyCode; } else { element.keyCode = e.charCode; } };
当使用 addEventListener 添加侦听器时,传递给该函数的第一个参数是一个 Event 对象,因此它将被分配给 e 参数(或为函数的第一个参数指定的任何名称)。
- 这就是 JS 的工作原理,你在每个事件回调中获得事件对象。它包含很多关于事件的信息。
- 不通过则功能不会停止,可选。继续 console.log 事件 (e) 并查看事件对象及其属性。当你看到它有什么时,它会更清楚。
您可以通过存储它在该匿名函数之外使用它,例如:
var myEvent; element.onkeypress = function(e) { myEvent = e; if(e.keyCode) { element.keyCode = e.keyCode; } else { element.keyCode = e.charCode; } }; console.log(myEvent);
但您应该知道事件对象仅与发生的特定事件有关,考虑到您应该决定是否真的需要这样做。
你问的参数e
是一个Event
对象,它
代表被触发的事件,它导致你的函数被执行。它不一定是 e
,您可以像所有其他函数参数一样将其命名为任何您想要的名称。
- 这个e是哪里来的?当我查看整个 javascript 文件时,e 似乎根本不存在。
您将无法在 javascript 文件中找到此 e
变量,因为
它实际上根本不存在,但来自 javascript 引擎执行
你的回调函数。
当你为某些事件提供回调函数时
(例如 element.onkeypress = function(e) { ... }
),你给出了
javascript 引擎函数 execute/call 当该事件触发时,以及
它 executes/calls 你的回调函数 它传递一个 Event
对象
代表刚刚发生的事件。 Javascript 可能正在做某事
像这样调用你的回调函数:
var e = new Event();
callbackFunction(e);
这就是 Event
对象 e
的来源。
- 为什么要把这个参数e传给函数?该功能是否会停止工作,如果 我不传e给它?
如果没有e
参数,函数不会停止工作。
但是,如果您需要访问有关导致您的事件的一些详细信息
要执行的函数,您将需要 e
参数来获取它们。
- 考虑下面的代码块,有一个事件变量 (e) 传递给 匿名内部函数。假设我想在 匿名函数(可能在 above/below 行 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
e
是 event
的缩写
创建事件的最简单方法是单击页面上的某个位置。
单击时,会触发 click
事件。这个 event
实际上是一个包含有关刚刚发生的动作的信息的对象。在此示例中,事件将包含点击坐标(例如 event.screenX
)、您点击的元素(event.target
)等信息。
现在,事件一直在发生,但是您对发生的所有事件都不感兴趣。但是,当您 对某个事件感兴趣时,就是在您将事件侦听器添加到您知道会创建事件的元素时 [1]。例如,您有兴趣了解 用户何时单击 'Subscribe' 按钮 并且您想在该事件发生时 做某事 。
为了对此事件做一些事情,您将 事件处理程序 绑定到您感兴趣的按钮。将处理程序绑定到元素的方法是 element.addEventListener(eventName, handler)
.
eventName
是一个字符串,它是您感兴趣的事件的名称,在本例中为 'click'
(对于 click
事件)。
处理程序只是一个函数,它在事件发生时做一些事情(它被执行)。默认情况下,处理程序函数在执行时 传递给 event
对象 (当您感兴趣的 event/action 发生时创建)作为参数。
将 event
定义为处理函数的参数是可选的,但有时(大多数时候),处理函数了解发生的事件很有用。当你做定义它时这就是你在你提到的函数中看到的e
。请记住,event
只是一个普通的 javascript 对象,上面有很多属性。
希望对您有所帮助。
有关详细信息,请阅读 Creating and Triggering Events
关于你的第三个问题,现在你应该知道你不能那样做,因为e
只有在事件发生时才存在。您可以拥有处理函数,它在执行时可以访问 e
对象,将其存储在某个全局变量中并对其进行处理。
[1] 这不完全正确,但更容易理解。更正确的说法是"add an event listener to the element you know will have events flow through it"。有关详细信息,请参阅 this
我会尽量用最抽象的方式来解释。真正的实现可能要复杂得多。因此,我将要使用的名称是假设的,但我希望它们确实有助于解释事物;)
浏览器中的每个节点都是 EventEmitter
class 的实现。 class 维护一个对象 events
,其中包含 key:value 对 eventType
(键):一个包含 listener
函数的数组(价值)。
EventEmitterclass中定义的两个函数是addEventListener
和fire
。
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
,并使用适当的参数 eventType
和 eventProperties
。
fire
循环遍历与特定 eventType 关联的数组。遍历数组,它调用数组中的每个 listener
函数,同时将 eventProperties
传递给它。
这就是 listener
函数的调用方式,仅使用特定的 eventType 注册,一旦 fire
被调用。
下面是演示。此演示中有 3 个 Actor。程序员、浏览器和用户。
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" 作为 eventType
传递,对象持有 eventProperties
。这会导致调用 "click" eventType
下所有已注册的 listener
函数。
如您所见,浏览器总是 使eventProperties
着火。作为一名程序员,您可能会也可能不会在 listener
函数中使用这些属性。
我发现在 stackoveflow 上有帮助的一些答案:
Where is an event registered with addEventListener stored?
Where are Javascript event handlers stored?