javascript最重要的关键字之一是this
。但是如果你不了解它的工作原理使用起来就会很困难。
下面我将介绍在事件处理中如何运用它。以后我会增加this
的其他用途。
所有者
这篇文章将要讨论的问题是:在函数doSomething()
中this
到底指向谁?
function doSomething(){
this.style.color ='#cc0000';
}
在javascript中,this
始终指向我们正在执行的这个函数的“所有者”,或者更确切地说,函数是哪个对象的方法this
就指向哪个对象。当我们在页面中定义函数doSomething()
的时候,他的所有者就是这个页面,或者说javascript的window
对象(或全局对象)。而一个onclick
属性的所有者是它所在的HTML元素。
这种“所属关系”是javascript的面向对象特性造成的,欲了解更多信息请阅读这篇对象亦是关联数组。
------------ window --------------------------------------
| /\ |
| | |
| this |
| ---------------- | |
| | HTML 元素 |<--this ----------------- |
| ---------------- | | doSomething()| |
| | | ----------------- |
| -------------------- |
| | onclick 属性 | |
| -------------------- |
| |
----------------------------------------------------------
如果我们直接执行doSomething()
,那么this
关键字指向window
,并且函数会去改变window
对象的style.color
,由于window
对象没有style
属性,这个函数会执行失败,并产生js错误。
拷贝
如果我们要合理地运用this就必须确保使用它的函数为正确的HTML元素所拥有,或换一种说法,我们必须把函数拷贝到onclick
属性上,传统的事件绑定模型很好地处理了这个问题。
element.onclick = doSomething;
函数被完整地拷贝到了onclick
属性上(现在成了一个方法),所以当事件处理函数被执行的时候this指向HTML元素并且它的color
会被改变。
------------ window --------------------------------------
| |
| |
| |
| ---------------- |
| | HTML元素 |<--this ----------------- |
| ---------------- | | doSomething()| |
| | | ----------------- |
| ----------------------- | |
| |doSomething()的一份拷贝| <-- 拷贝函数 |
| ----------------------- |
| |
----------------------------------------------------------
这里有个小技巧是我们可以把函数拷贝到多个事件处理器上,每次this
都能指向正确地HTML元素:
------------ window --------------------------------------
| |
| |
| |
| ---------------- |
| | HTML元素 |<--this ----------------- |
| ---------------- | | doSomething()| |
| | | ----------------- |
| ----------------------- | |
| |doSomething()的一份拷贝| <-- 拷贝函数 |
| ----------------------- | |
| | |
| ----------------------- | |
| | 另一个HTML元素 |<--this | |
| ----------------------- | | |
| | | | |
| ----------------------- | |
| |doSomething()的一份拷贝| <-- 拷贝函数 |
| ----------------------- |
| |
----------------------------------------------------------
这样才是比较充分地使用this
,每次函数被执行的时候this都指向触发了这个事件的HTML元素,这个HTML元素“拥有”了doSomething()
的一份拷贝。
调用
然而如果你使用行内事件绑定方式
<element onclick="doSomething()">
你没有拷贝函数!而是调用了这个函数。其中的区别是很关键的。这里的onclick
属性并没有包含任何实际的函数,而只是一个触发了这个函数:
doSomething();
他只是说了句“找到doSomething()
并执行它”,当我们找到doSomething()
的时候this
关键字再一次指向了全局的window
对象,并且函数会返回错误提示。(chrome的this指向的正是window)
------------ window --------------------------------------
| /\ |
| | |
| this |
| ---------------- | |
| | HTML元素 |<--this ----------------- |
| ---------------- | | doSomething()| |
| | | ----------------- |
| ----------------------- /\ |
| |找到doSomething() | | |
| |并执行它 |---- 对函数的调用 |
| ----------------------- |
| |
----------------------------------------------------------
区别
如果你想通过this
来获得触发了这个事件的HTML元素,就必须确保this
关键字确实被写入到了onclick
属性里面,只有这种情况下它才会指向该函数所绑定到的HTML元素。所以如果你测试下面这段
element.onclick = doSomething;
alert(element.onclick)
你将得到:
function doSomething()
{
this.style.color ='#cc0000';
}
可以看到,this
关键字出现在onclick
方法里面,因此它会指向HTML元素。
但是如果你测试以下这段:
<element onclick="doSomething()">
alert(element.onclick)
会得到
function onclick()
{
doSomething()
}
这只是一个对函数doSomething()
的调用,this关键字并没有出现在onclick
方法里面,所以它不会指向HTML元素。
例子——拷贝
在下面的情况下this
会写入onclick
方法内:
element.onclick = doSomething
element.addEventListener('click',doSomething,false)
element.onclick =function(){this.style.color ='#cc0000';}
<element onclick="this.style.color = '#cc0000';">
例子——调用
下面这些情况this
指向window
:
element.onclick =function(){doSomething()}
element.attachEvent('onclick',doSomething) (ie报错无法设置属性“color”的值: 对象为 null 或未定义)
<element onclick="doSomething()">
注意这里出现了attachEvent()
,微软事件绑定模型的一个严重的缺点是attachEvent()
只建立了对函数的调用但没有拷贝。所以有些时候我们无法知道是哪个HTML元素触发了这个事件。
二者结合
当使用行内事件绑定方式时也可以把this
传给函数,使你仍然可以在函数内部使用它:
<element onclick="doSomething(this)">
function doSomething(obj){
// this出现在了事件处理器内并且传给了函数
// obj现在指向HTML元素,所以你可以做以下操作
obj.style.color ='#cc0000';
}
本文翻译自PPK的The this keyword。
via:http://biaoge.me/2010/01/289
有时出现错误:
Object [object DOMWindow] has no method ‘attachEvent’
This error occurs when trying bind an event, using window.attachEvent
as a function, which only works in Internet Explorer.
Your code might look something like this:
var myFunction = function(){ alert("foo"); } window.attachEvent("onclick", myFunction);
To fix this, use the following code (remember to remove “on” from “onclick” etc):
var myFunction = function(){ alert("foo"); } window.addEventListener("click", myFunction,false);
要注意自己的代码到底运行在哪个浏览器上。