抄自:《悟透JavaScript》 第88页
我们先看一个例子:
<html>
<body>
<div onclick=" alert('This is a ' + this.tagname)">Click Me!</div>
</body>
</html>
这个html文件运行时,单击div就会弹出“This is a DIV”。上面的this参数就是触发事件的DOM对象本身。
进行静态绑定时,我们经常会犯一个小错误,就是把事件绑定写成了下面的形式:
<div onclick="ClickMe">Click Me!</div> //错误的, ClickMe 后面没有括号()
这种写法的目的本是要将<div>元素的onclick事件绑定到ClickMe函数上,但运行时却提示“ClickMe未定义”的错误。为什么不能这样写呢?这得从静态绑定事件的原理说起。
当我们写下onclick="..."的时候,实际上可以看成下面的等价形式:
aDiv.onclick = function(){...};
也就是说,标签的事件属性的值,也就是引号内的内容,将被认为是一段JavaScript代码,这段代码也将成为一个匿名函数内的代码,而这个匿名函数才是真正的事件处理函数。显然,单独的"ClickMe"根本就不是一个有效的JavaScript语句,所以这种写法就是错误的。
我们再来看看另一种静态绑定形式,这种形式虽不一定是错误的,但有时却会出问题:
<div onclick="ClickMe()">Click Me!</div> //不推荐, this是全局的window对象而不是DOM对象本身
同样,它等效于下面的代码:
aDiv.onclick = function(){ClickMe()}; //这里的this并非触发事件的DOM对象本身,而是全局的window对象。
这个匿名函数并没有任何错误。但要注意的是,此时把ClickMe函数内的this参数当作触发事件的DOM对象本身,就会出问题了。这里的this并非触发事件的DOM对象本身,而是全局的window对象。
为什么会这样呢?
当事件触发时,浏览器会调用aDiv.onclick(),也就是调用这个匿名函数。显然,此时匿名函数的this参数将是触发事件的DOM对象。并且,也只有在这个匿名函数的作用域上下文中,this参数才是响应事件的DOM对象。从这个匿名函数中调用ClickMe()时,并没有把this传递给ClickMe函数。作用域跳到ClickMe函数内时,this只是默认的window对象。所以,这种情况下,你得不到触发事件的DOM对象。
那么,静态绑定事件应该怎样写呢?
显然,第一种写法肯定不行。而第二种写法对于不关心this参数,或者无须判断当前响应事件的DOM对象时,也是完全可行的。如果要让事件处理代码知道当前DOM对象是谁,可以给事件处理函数定义一个参数,并将当前的this带进去。如下所示:
<div onclick="ClickMe(this)">Click Me!</div> //推荐, this是DOM对象本身
还可以利用函数的call或者apply方法来传递默认的this参数,如下所示:
<div onclick="ClickMe.call(this)">Click Me!</div> //推荐, this是DOM对象本身
所以建议用后面的两种方法进行静态事件绑定。
我们先看一个例子:
<html>
<body>
<div onclick=" alert('This is a ' + this.tagname)">Click Me!</div>
</body>
</html>
这个html文件运行时,单击div就会弹出“This is a DIV”。上面的this参数就是触发事件的DOM对象本身。
进行静态绑定时,我们经常会犯一个小错误,就是把事件绑定写成了下面的形式:
<div onclick="ClickMe">Click Me!</div> //错误的, ClickMe 后面没有括号()
这种写法的目的本是要将<div>元素的onclick事件绑定到ClickMe函数上,但运行时却提示“ClickMe未定义”的错误。为什么不能这样写呢?这得从静态绑定事件的原理说起。
当我们写下onclick="..."的时候,实际上可以看成下面的等价形式:
aDiv.onclick = function(){...};
也就是说,标签的事件属性的值,也就是引号内的内容,将被认为是一段JavaScript代码,这段代码也将成为一个匿名函数内的代码,而这个匿名函数才是真正的事件处理函数。显然,单独的"ClickMe"根本就不是一个有效的JavaScript语句,所以这种写法就是错误的。
我们再来看看另一种静态绑定形式,这种形式虽不一定是错误的,但有时却会出问题:
<div onclick="ClickMe()">Click Me!</div> //不推荐, this是全局的window对象而不是DOM对象本身
同样,它等效于下面的代码:
aDiv.onclick = function(){ClickMe()}; //这里的this并非触发事件的DOM对象本身,而是全局的window对象。
这个匿名函数并没有任何错误。但要注意的是,此时把ClickMe函数内的this参数当作触发事件的DOM对象本身,就会出问题了。这里的this并非触发事件的DOM对象本身,而是全局的window对象。
为什么会这样呢?
当事件触发时,浏览器会调用aDiv.onclick(),也就是调用这个匿名函数。显然,此时匿名函数的this参数将是触发事件的DOM对象。并且,也只有在这个匿名函数的作用域上下文中,this参数才是响应事件的DOM对象。从这个匿名函数中调用ClickMe()时,并没有把this传递给ClickMe函数。作用域跳到ClickMe函数内时,this只是默认的window对象。所以,这种情况下,你得不到触发事件的DOM对象。
那么,静态绑定事件应该怎样写呢?
显然,第一种写法肯定不行。而第二种写法对于不关心this参数,或者无须判断当前响应事件的DOM对象时,也是完全可行的。如果要让事件处理代码知道当前DOM对象是谁,可以给事件处理函数定义一个参数,并将当前的this带进去。如下所示:
<div onclick="ClickMe(this)">Click Me!</div> //推荐, this是DOM对象本身
还可以利用函数的call或者apply方法来传递默认的this参数,如下所示:
<div onclick="ClickMe.call(this)">Click Me!</div> //推荐, this是DOM对象本身
所以建议用后面的两种方法进行静态事件绑定。