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 相关文章推荐
利用js实现选项卡的特别效果的实例
Mar 03 Javascript
JSONP跨域的原理解析及其实现介绍
Mar 22 Javascript
js检测浏览器版本、核心、是否移动端示例
Apr 24 Javascript
JavaScript中的setUTCDate()方法使用详解
Jun 11 Javascript
js实现一键复制功能
Mar 16 Javascript
vue一步步实现alert功能
Jul 05 Javascript
Vue.js自定义事件的表单输入组件方法
Mar 08 Javascript
详解webpack-dev-server 设置反向代理解决跨域问题
Apr 18 Javascript
vue使用better-scroll实现下拉刷新、上拉加载
Nov 23 Javascript
PostgreSQL Node.js实现函数计算方法示例
Feb 12 Javascript
Node.js Windows Binary二进制文件安装方法
May 16 Javascript
深入浅析vue中cross-env的使用
Sep 12 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
一个程序下载的管理程序(四)
2006/10/09 PHP
php中通过虚代理实现延迟加载的实现代码
2011/06/10 PHP
php随机显示图片的简单示例
2014/02/15 PHP
php字符串操作针对负值的判断分析
2016/07/28 PHP
php 如何禁用eval() 函数实例详解
2016/12/01 PHP
php获取微信共享收货地址的方法
2017/12/21 PHP
laravel 如何实现引入自己的函数或类库
2019/10/15 PHP
js中格式化日期时间型数据函数代码
2010/11/08 Javascript
javascript文本模板用法实例
2015/07/31 Javascript
JS基于myFocus库实现各种功能的tab选项卡切换效果
2015/09/19 Javascript
JS小数转换为整数的方法分析
2017/01/07 Javascript
Bootstrap模态窗口源码解析
2017/02/08 Javascript
VUE 更好的 ajax 上传处理 axios.js实现代码
2017/05/10 Javascript
使用react-router4.0实现重定向和404功能的方法
2017/08/28 Javascript
VueJs组件prop验证简单介绍
2017/09/12 Javascript
node.js 用socket实现聊天的示例代码
2017/10/17 Javascript
用jQuery将JavaScript对象转换为querystring查询字符串的方法
2018/11/12 jQuery
jQuery事件模型默认行为执行顺序及trigger()与 triggerHandler()比较实例分析
2020/04/30 jQuery
详解Vue.js 响应接口
2020/07/04 Javascript
[01:36:57]【09DOTA2第一视角】小骷髅
2014/04/16 DOTA
[46:58]完美世界DOTA2联赛PWL S3 Forest vs LBZS 第一场 12.17
2020/12/19 DOTA
基于scrapy实现的简单蜘蛛采集程序
2015/04/17 Python
Python+django实现文件下载
2016/01/17 Python
Python 内置函数memoryview(obj)的具体用法
2017/11/23 Python
python3结合openpyxl库实现excel操作的实例代码
2018/09/11 Python
python用线性回归预测股票价格的实现代码
2019/09/04 Python
Booking.com荷兰:全球酒店网上预订
2017/08/22 全球购物
英国最出名高街品牌:Forever Unique
2018/02/24 全球购物
幼儿园园长岗位职责
2013/11/26 职场文书
八年级音乐教学反思
2014/01/09 职场文书
护士自我评价
2014/02/01 职场文书
文明餐桌行动实施方案
2014/02/19 职场文书
企业承诺书怎么写
2014/05/24 职场文书
教师工作自我鉴定范文
2014/09/14 职场文书
2014年党员干部四风问题自我剖析材料
2014/09/29 职场文书
Spring Cache和EhCache实现缓存管理方式
2021/06/15 Java/Android