在事件处理函数中的 this
在 JavaScript 中,this
是一个很重要的关键字。此前写过一篇文章:JavaScript中 的 this 真没那么难理解。本文内容主要是,针对事件处理函数中如何使用 this
的几种方法及区别。
一、Owner
我们将在本文讨论的问题是:在函数 doSomething()
中 this
指向的是什么?
注意,本文通篇均在非严格模式下进行。
<script>
function doSomething() {
this.style.color = '#c00'
}
</script>
在 JavaScript 中, this
总是指我们正在执行的函数的“owner”,或者更确切地说,是指函数作为其方法的对象。当我们在页面中定义我们函数 doSomething()
时,它的“owner”是页面,或者更确切地说,是 JavaScript 的 window
对象(或全局对象)。但是,onclick
属性归它所属的 HTML 元素所有。
这种“ownership”是 JavaScript 面向对象方法的结果。有关更多信息,请参阅作为关联数组的对象页面。
------------ window --------------------------------------
| / \ |
| | |
| this |
| ---------------- | |
| | HTML element | <-- this ----------------- |
| ---------------- | | doSomething() | |
| | | ----------------- |
| -------------------- |
| | onclick property | |
| -------------------- |
| |
----------------------------------------------------------
如果我们在没有任何准备的情况下执行 doSomething()
,则 this
关键字指向 window
对象,该函数会尝试更改 window
对象的 style.color
。由于 window
没有 style
对象,该函数会失败并产生 JavaScript 错误(TypeError)。
二、Copying
如果我们想充分利用 this
,我们必须注意使用它的函数是由正确的 HTML 元素“拥有”的。换句话说,我们必须将函数复制到我们的 onclick
属性。传统的事件注册会处理它。
element.onclick = doSomething
该函数被完整地复制到 onclick
属性(现在变成了一个方法)。因此,如果执行事件处理程序,this
会指向 HTML 元素,并且它的 color
会发生变化。
------------ window --------------------------------------
| |
| |
| |
| ---------------- |
| | HTML element | <-- this ----------------- |
| ---------------- | | doSomething() | |
| | | ----------------- |
| ----------------------- | |
| |copy of doSomething()| <-- copy function |
| ----------------------- |
| |
----------------------------------------------------------
当然是我们可以将函数复制到多个事件处理程序。每次 this
将指向正确的 HTML 元素:
------------ window --------------------------------------
| |
| |
| |
| ---------------- |
| | HTML element | <-- this ----------------- |
| ---------------- | | doSomething() | |
| | | ----------------- |
| ----------------------- | |
| |copy of doSomething()| <-- copy function |
| ----------------------- | |
| | |
| ----------------------- | |
| | another HTML element| <-- this | |
| ----------------------- | | |
| | | | |
| ----------------------- | |
| |copy of doSomething()| <-- copy function |
| ----------------------- |
| |
----------------------------------------------------------
因此,你可以最大程度地使用它。每次调用该函数时, this
指的是当前正在处理事件的 HTML 元素,即“拥有” doSomething()
副本的 HTML 元素。
三、Referring
但是,如果你使用内联事件注册:
<element onclick="doSomething()">doSomething...</element>
你不要复制功能!相反,你指向它,差异至关重要。onclick
属性不包含实际的函数,而只是一个函数调用:
doSomething()
所以这相当于,前往 doSomething()
并执行它。当我们到达 doSomething()
时,this
关键字再次指向全局 window
对象,并且该函数返回错误消息(TypeError)。
------------ window --------------------------------------
| / \ |
| | |
| this |
| ---------------- | |
| | HTML element | <-- this ----------------- |
| ---------------- | | doSomething() | |
| | | ----------------- |
| ----------------------- / \ |
| | go to doSomething() | | |
| | and execute it | ---- reference to |
| ----------------------- function |
| |
----------------------------------------------------------
四、The difference
如果你想使用 this
来访问正在处理事件的 HTML 元素,你必须确保 this
关键字实际上已写入 onclick
属性。只有在这种情况下,this
才指向事件处理程序注册到的 HTML 元素。因此,如果你这样处理:
element.onclick = doSomething
alert(element.onclick)
你将会得到:
function doSomething() {
this.style.color = '#c00'
}
如你所见,this
关键字存在于 onclick
方法中。因此 this
指向 HTML 元素。
但是,如果你这样处理:
<element onclick="doSomething()">doSomething...</element>
alert(element.onclick)
你得到的是:
function onclick(event) {
doSomething()
}
这仅仅是对函数 doSomething()
的引用。onclick
方法中不存在 this
关键字,因此 this
不指向 HTML 元素。
五、Examples - copying
以下情况 this
会写入 onclick
方法:
element.onclick = doSomething
element.addEventListener('click', doSomething, false)
element.onclick = function () { this.style.color = '#c00' }
<element onclick="this.style.color = '#c00'">doSomething...</element>
六、Examples - referring
以下情况 this
指向 window
对象:
element.onclick = function () { doSomething() }
element.attachEvent('onclick', doSomething)
<element onclick="doSomething()">doSomething...</element>
请注意 attachEvent()
的存在。 Microsoft 事件注册模型的主要缺点是 attachEvent()
创建对函数的引用而不复制它。因此,有时无法知道当前是哪个 HTML 处理该事件。
七、Combination
使用内联事件注册时,你还可以将 this
发送到该函数,以便你仍然可以使用它:
<element onclick="doSomething(this)">doSomething...</element>
function doSomething(obj) {
// `this` is present in the event handler and is sent to the function
// `obj` now refers to the HTML element, so we can do
obj.style.color = '#c00'
}
八、TODO List
- Introduction to Events
- Objects as associative arrays
- Traditional event registration model
- Early event handlers
- Advanced event registration models