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 相关文章推荐
使用jquery菜单插件HoverTree仿京东无限级菜单
Dec 18 Javascript
jQuery实现拖动调整表格单元格大小的代码实例
Jan 13 Javascript
jQuery实现高亮显示的方法
Mar 10 Javascript
JavaScript将XML转成JSON的方法
Mar 12 Javascript
js实现表单Radio切换效果的方法
Aug 17 Javascript
javascript中substring()、substr()、slice()的区别
Aug 30 Javascript
js实现抽奖效果
Mar 27 Javascript
简单谈谈js的数据类型
Sep 25 Javascript
用React-Native+Mobx做一个迷你水果商城APP(附源码)
Dec 25 Javascript
javascript数组拍平方法总结
Jan 20 Javascript
Vue+Express实现登录状态权限验证的示例代码
May 05 Javascript
使用 Element UI Table 的 slot-scope方法
Oct 10 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页面消耗内存过大的处理办法
2013/03/18 PHP
解决laravel5.4下的group by报错的问题
2019/10/16 PHP
thinkphp框架实现路由重定义简化url访问地址的方法分析
2020/04/04 PHP
用JavaScript实现仿Windows关机效果
2007/03/10 Javascript
重载toString实现JS HashMap分析
2011/03/13 Javascript
借助script进行Http跨域请求:JSONP实现原理及代码
2013/03/19 Javascript
JavaScript面对国际化编程时的一些建议
2015/06/24 Javascript
jquery实现左右滑动菜单效果代码
2015/08/27 Javascript
Angular.js实现注册系统的实例详解
2016/12/18 Javascript
jQuery命名空间与闭包用法示例
2017/01/12 Javascript
js date 格式化
2017/02/15 Javascript
NodeJS配置HTTPS服务实例分享
2017/02/19 NodeJs
JavaScript登录记住密码操作(超简单代码)
2017/03/22 Javascript
详解如何构建Angular项目目录结构
2017/07/13 Javascript
webpack4.0 入门实践教程
2018/10/08 Javascript
详解vuex的简单todolist例子
2019/07/14 Javascript
梳理一下vue中的生命周期
2020/12/30 Vue.js
使用pdb模块调试Python程序实例
2015/06/02 Python
使用numpy和PIL进行简单的图像处理方法
2018/07/02 Python
python获取磁盘号下盘符步骤详解
2019/06/19 Python
python3实现斐波那契数列(4种方法)
2019/07/15 Python
Python socket实现的文件下载器功能示例
2019/11/15 Python
Python AutoCAD 系统设置的实现方法
2020/04/01 Python
浅析Python 抽象工厂模式的优缺点
2020/07/13 Python
Python3.8安装Pygame教程步骤详解
2020/08/14 Python
html5-websocket基于远程方法调用的数据交互实现
2012/12/04 HTML / CSS
JDK安装目录下有哪些内容
2014/08/25 面试题
最新会计专业求职信范文
2014/01/28 职场文书
《小儿垂钓》教学反思
2014/02/23 职场文书
教师网络培训感言
2014/03/09 职场文书
公益广告语集锦
2014/03/13 职场文书
财务情况说明书范文
2014/05/06 职场文书
Nest.js参数校验和自定义返回数据格式详解
2021/03/29 Javascript
Vue3中toRef与toRefs的区别
2022/03/24 Vue.js
浅谈Redis的事件驱动模型
2022/05/30 Redis
Java中的Kafka为什么性能这么快及4大核心详析
2022/09/23 Java/Android