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 相关文章推荐
Gird组件 Part-3:范例RSSFeed Viewer
Mar 10 Javascript
漂亮的widgets,支持换肤和后期开发新皮肤
Apr 23 Javascript
Eclipse去除js(JavaScript)验证错误
Feb 11 Javascript
常用的jQuery前端技巧收集
Dec 24 Javascript
DOM操作原生js 的bug,使用jQuery 可以消除的解决方法
Sep 04 Javascript
js实现加载页面就自动触发超链接的示例
Aug 31 Javascript
Angular实现搜索框及价格上下限功能
Jan 19 Javascript
vue 登录滑动验证实现代码
Aug 24 Javascript
JS+canvas画布实现炫酷的旋转星空效果示例
Feb 13 Javascript
深入浅析vue-cli@3.0 使用及配置说明
May 08 Javascript
在vue-cli创建的项目中使用sass操作
Aug 10 Javascript
使用Canvas绘制一个游戏人物属性图
Mar 25 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
PHP编程之设置apache虚拟目录
2016/07/08 PHP
详解php中serialize()和unserialize()函数
2017/07/08 PHP
用JavaScript获取网页中的js、css、Flash等文件
2006/12/20 Javascript
javascript flash下fromCharCode和charCodeAt方法使用说明
2008/01/12 Javascript
Javascript select下拉框操作常用方法
2009/11/09 Javascript
js中top/parent/frame概述及案例应用
2013/02/06 Javascript
jQuery回调函数的定义及用法实例
2014/12/23 Javascript
vue.js入门教程之基础语法小结
2016/09/01 Javascript
Express之get,pos请求参数的获取
2017/05/02 Javascript
详谈表单重复提交的三种情况及解决方法
2017/08/16 Javascript
javascript如何用递归写一个简单的树形结构示例
2017/09/06 Javascript
vue微信分享到朋友圈 vue微信发送给好友
2018/11/28 Javascript
Vue 指令实现按钮级别权限管理功能
2019/04/23 Javascript
如何利用vue+vue-router+elementUI实现简易通讯录
2019/05/13 Javascript
webpack.DefinePlugin与cross-env区别详解
2020/02/23 Javascript
vant 解决tab切换插件标题样式自定义的问题
2020/11/13 Javascript
[03:06]3分钟带你回顾DOTA2完美盛典&完美大师赛
2017/12/06 DOTA
[40:31]Secret vs Alliacne 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
Python实现监控程序执行时间并将其写入日志的方法
2015/06/30 Python
以一个投票程序的实例来讲解Python的Django框架使用
2016/02/18 Python
Python reduce()函数的用法小结
2017/11/15 Python
浅谈Python中的zip()与*zip()函数详解
2018/02/24 Python
Selenium定时刷新网页的实现代码
2018/10/31 Python
Django Docker容器化部署之Django-Docker本地部署
2019/10/09 Python
基于Python实现ComicReaper漫画自动爬取脚本过程解析
2019/11/11 Python
python编写一个会算账的脚本的示例代码
2020/06/02 Python
PyCharm安装PyQt5及其工具(Qt Designer、PyUIC、PyRcc)的步骤详解
2020/11/02 Python
英国最大的在线运动补充剂商店:Discount Supplements
2017/06/03 全球购物
网络工程师专家职业发展路线
2014/02/14 职场文书
2014年图书馆工作总结
2014/11/25 职场文书
学习雷锋精神活动总结
2015/02/06 职场文书
入党个人总结范文
2015/03/02 职场文书
护士求职自荐信范文
2015/03/04 职场文书
Django一小时写出账号密码管理系统
2021/04/29 Python
win server2012 r2服务器共享文件夹如何设置
2022/06/21 Servers
Pytorch中expand()的使用(扩展某个维度)
2022/07/15 Python