PPK 谈 JavaScript 的 this 关键字 [翻译]


Posted in Javascript onSeptember 29, 2009

下面先讲如何在event handling(事件处理)中用它,再接着是讲 this 的其他用法。

自己本身

先来看看函数 doSomething() 里的 this 到底是指向(refer to)了什么?

function doSomething() {
  this.style.color = '#cc0000';
}

JavaScript的 this 总指向所运行的函数“自己本身”。也就是说,它是一种指向函数对象的方法。在页面中定义 doSomething() 函数,自己本身是指页面。也就是说,是指 JavaScript 的 window 对象(全局对象)。而 onclick 属性它自己本身是属 HTML 元素所有。

这个“所有权”是 JavaScript 的 OO(面向对象)特性的后果。在 把对象作关联数组 页面中有更多信息。

------------ window --------------------------------------
|                     / \      |
|                      |      |
|                     this     |
|  ----------------            |      |
|  | HTML element | <-- this     ----------------- |
|  ----------------   |      | doSomething() | |
|        |     |      ----------------- |
|     --------------------             |
|     | onclick property |             |
|     --------------------             |
|                            |
----------------------------------------------------------

如果 doSomething() 运行时没有任何与之预留相关的话,关键字 this 指向 window(窗口) ,该函数将会改动 window 的 style.color。而 window 没有 style 这样的对象,所以该函数会引发 JavaScript 的错误。

拷贝(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() 的拷贝)。

指向(referring)

要是用 行内事件注册呢?

<element onclick="doSomething()">

这里没有拷贝函数,而是指向它,有什么不一样呢? 这个 onclick 属性没有包含实际函数,而只是一个函数调用。

doSomething();

上面的意思是:“到 doSomething() 那里去执行它”。在doSomething()里面,this 关键字再次指向全局 window 对象,那么函数会返回错误的消息。

------------ window --------------------------------------
|                     / \      |
|                      |      |
|                     this     |
|  ----------------            |      |
|  | HTML element | <-- this     ----------------- |
|  ----------------   |      | doSomething() | |
|        |     |      ----------------- |
|     -----------------------     / \      |
|     | go to doSomething() |     |      |
|     | and execute it   | ---- reference to   |
|     -----------------------    function    |
|                            |
----------------------------------------------------------

不一样?

如果是用 this 去访问 HTML 元素来处理事件的话,那么必须肯定它实际是写入了 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 = function () {doSomething()}
element.attachEvent('onclick',doSomething)
<element onclick="doSomething()">

例子-指向

在下面示例中,this 指向 window:

element.onclick = function () {doSomething()}
element.attachEvent('onclick',doSomething)
<element onclick="doSomething()">

要注意上面的 attachEvent。它的缺点是微软事件注册模型,它创建了指向该函数,而且没有拷贝它。所以有时不可能弄清楚 HTML 当前的处理事件是哪个。

结合

使用行内事件注册时,也可以把 this 发送到函数。所以可以这么用:

<element onclick="doSomething(this)">
 
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 = '#cc0000';
}
Javascript 相关文章推荐
用正则获取指定路径文件的名称
Feb 27 Javascript
有关js的变量作用域和this指针的讨论
Dec 16 Javascript
Jquery的hover方法让鼠标经过li时背景变色
Sep 06 Javascript
首页图片漂浮效果示例代码
Jun 05 Javascript
JavaScript中的console.assert()函数介绍
Dec 29 Javascript
javascript实现的右下角弹窗实例
Apr 24 Javascript
js实现select二级联动下拉菜单
Apr 17 Javascript
完美的js div拖拽实例代码
Sep 24 Javascript
解决vue-cli中stylus无法使用的问题方法
Jun 19 Javascript
jQuery封装placeholder效果实现方法,让低版本浏览器支持该效果
Jul 08 jQuery
vue + element-ui的分页问题实现
Dec 17 Javascript
JS实现倒序输出的几种常用方法示例
Apr 13 Javascript
一个JS小玩意 几个属性相加不能超过一个特定值.
Sep 29 #Javascript
IE FF OPERA都可用的弹出层实现代码
Sep 29 #Javascript
javascript 表单验证常见正则
Sep 28 #Javascript
javascript 页面划词搜索JS
Sep 28 #Javascript
jquery 模式对话框终极版实现代码
Sep 28 #Javascript
javascript的onchange事件与jQuery的change()方法比较
Sep 28 #Javascript
支持ie与FireFox的剪切板操作代码
Sep 28 #Javascript
You might like
Classes and Objects in PHP5-面向对象编程 [1]
2006/10/09 PHP
用在PHP里的JS打印函数
2006/10/09 PHP
PHP经典的给图片加水印程序
2006/12/06 PHP
PHP图片处理之使用imagecopyresampled函数裁剪图片例子
2014/11/19 PHP
PHP魔术方法__GET、__SET使用实例
2014/11/25 PHP
PHP实现将科学计数法转换为原始数字字符串的方法
2014/12/16 PHP
IE6弹出“已终止操作”的解决办法
2010/11/27 Javascript
JavaScript中“+”的陷阱深刻理解
2012/12/04 Javascript
在jQuery中 关于json空对象筛选替换
2013/04/15 Javascript
Jquery post传递数组方法实现思路及代码
2013/04/28 Javascript
JS中的二叉树遍历详解
2016/03/18 Javascript
jQuery解决IE6、7、8不能使用 JSON.stringify 函数的问题
2016/05/31 Javascript
早该知道的7个JavaScript技巧
2016/06/21 Javascript
js canvas仿支付宝芝麻信用分仪表盘
2016/11/16 Javascript
angular5 子组件监听父组件传入值的变化方法
2018/09/30 Javascript
vue多次循环操作示例
2019/02/08 Javascript
Javascript异步编程async实现过程详解
2020/04/02 Javascript
vue实现两个区域滚动条同步滚动
2020/12/13 Vue.js
[02:54]DOTA2英雄基础教程 撼地者
2014/01/14 DOTA
Python中urllib+urllib2+cookielib模块编写爬虫实战
2016/01/20 Python
Python利用flask sqlalchemy实现分页效果
2020/08/02 Python
Python selenium实现微博自动登录的示例代码
2018/05/16 Python
Sanic框架Cookies操作示例
2018/07/17 Python
在PyCharm下使用 ipython 交互式编程的方法
2019/01/17 Python
Python如何实现动态数组
2019/11/02 Python
利用python绘制数据曲线图的实现
2020/04/09 Python
python使用opencv resize图像不进行插值的操作
2020/07/05 Python
关于老式浏览器兼容HTML5和CSS3的问题
2016/06/01 HTML / CSS
HTML5自定义元素播放焦点图动画的实现
2019/09/25 HTML / CSS
Html5实现首页动态视频背景的示例代码
2019/09/25 HTML / CSS
高三英语教学反思
2014/01/13 职场文书
会计员岗位职责
2014/03/15 职场文书
拾金不昧锦旗标语
2014/06/27 职场文书
党支部群众路线整改措施思想汇报
2014/10/10 职场文书
租房协议书范例
2014/10/14 职场文书
幼儿园综治宣传月活动总结
2015/05/07 职场文书