关于javascript中this关键字(翻译+自我理解)


Posted in Javascript onOctober 20, 2010

下文有大概70%的内容出自http://www.quirksmode.org/js/this.html,另外30%是我自己对它的理解和感想。希望能对有需要的人一点帮助。。。

首先,先看一个很典型的关于this关键字题目:

var name = 'hong' 
var obj = { 
name: 'ru', 
getName: function(){ 
return function(){ 
return this.name; 
}; 
} 
} 
alert(obj.getName()());

这里也不卖关子了,执行结果为:hong
稍微改下代码:
var name = 'hong' 
var obj = { 
name: 'ru', 
getName: function(){ 
var that = this; 
return function(){ 
return that.name; 
}; 
} 
} 
alert(obj.getName()());

执行结果为:ru
执行结果为:ru

关于出现这种结果的原因,下面会细细讨论。
【函数的拥有者】
要解释this,要先说这个概念。在JavaScript里,this始终指向我们当前正在执行的函数的“拥有者”。更为确切的说:是指向把这个函数作为方法的对象。
这句话怎么理解,我们可以看看下面的例子:

/* -- test1 -- */ 
function test1 () { 
this.title = 'me'; 
alert(window['title']); 
alert(this === window); //true 
} 
test1();

执行结果为:me, true
在上例中,this是指向window对象的。并把window这个对象的title属性写为'me',因为test1是个顶级函数,所以它的拥有者是window对象,或者说它是window对象的一个方法。这个应该不难理解。比如上面调用test1()时,也可以写成 window.test1();这样的明了了。

接下来,我们建一个div,并把test1作为方法赋给div的onclick属性:

<div id="o" style="width:50px;height:50px;border:4px solid #333">me!</div> 
<script type="text/javascript"> 
/* -- test1 -- */ 
function test1 () { 
this.title = 'me'; 
alert(window['title']); 
alert(this === window); 
} 
var o = document.getElementById('o'); 
o.onclick = test1; 
</script>

点击div结果为:undefined, false; 同时我们用firebug可以看到‘me'这个属性值其实是被赋给了id为‘o'的这个HtmlObject
关于javascript中this关键字(翻译+自我理解)
显而易见,此时this指向了这个div,也就是说,test1()的拥有者变成了div这个HtmlObject,或者说它变成了div的onclick方法来调用。这种情况应该还是容易理解的。
下面我们接着改代码,就改一个地方:
o.onclick = test1(); // 注意:这里加了个括号

把上面代码的最后一句改成这样后,点击div运行的结果为:me, true
变成了和第一种情况一样了,this指向了window。有人会纳闷,觉得没什么区别,其实是有区别的。这里涉及到函数的copy和refer的问题。

【函数的Copy】

如果通过

o.onclick = test1;

这样的方式的话,其实是把test1() 这个函数Copy给了对象 o 的 onclick 属性。因此test1的拥有者变成了 o 这个对象。

如果通过

o.onclick = test1();

这样的方式的话,本质上是指当获取到点击事件的handle时,指引它去执行test1()函数。注意是指引去执行而不是赋给它去执行。test1()的拥有者没变,还是window.

【函数的Refer】

同上,我们通过inline的方式把调用写到html里来调用的话,还是refer的方式

<div id="o" style="width:50px;height:50px;border:4px solid #333" onclick="test1()">me!</div>

点击div执行结果还是表示this指向window。

【函数copy的例子】

element.onclick = doSomething 
element.addEventListener('click',doSomething,false) 
element.onclick = function () {this.style.color = '#cc0000';} 
<element onclick="this.style.color = '#cc0000';">

这几种方式都会使this的指向变为当前调用的object。

【函数refer的例子】

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

这几种方式都不会改变函数的拥有者,其中要注意的是addEventListener和attachEvent是不一致的,因为attachEvent其实是建立了一个reference到了doSomething,而不是copy了这个函数。

【用call的方式】
刚才我们说了,写成<element onclick="test()">的方式还是不能让test()的拥有者变成<element>,那我们可以这样做

<element onclick="test(this)"> 
function (o) { 
o.title = 'me'; 
}

这样显式的调用是可以的。或者,用call或apply这种对象冒充的继承方式也可以
<element onclick="test.call(this)"> 
function test () { 
this.title = 'me'; 
}

这也是对象冒充最典型的方式。

【自由变量问题】

写了这么长,我们还是回到最开始的那个问题:

var name = 'hong' 
var obj = { 
name: 'ru', 
getName: function(){ 
return function(){ 
return this.name; 
}; 
} 
} 
alert(obj.getName()());

为什么这种方式得到的结果会是:hong 呢?重点在
return function(){ 
return this.name; 
};

对比一下上面写的函数refer的例子,不难发现,返回的这个匿名函数的调用方式和onclick = function () {doSomething()} 如出一辙。所以这种方式并不会改变这个function的拥有者,它虽然是个嵌套函数,但是它的声明却是顶级的。其中的this指向的是window。

而第二种方式是强制在getName()中把this赋给了that,也就是说,that.name其实和getName()中的this.name是一样的。而在getName的上下文中,它的拥有者是obj这个对象,所以this会指向obj,故this.name === obj.name;

绕了这么一大圈不知道有没有把各位绕明白。

其实可以这样总结:在this所在的函数上下文中,如果这个函数不是以“方法”的形式被调用的话,那么这个this会指向window对象,否则会指向这个函数的拥有者。

Javascript 相关文章推荐
javascript 写类方式之十
Jul 05 Javascript
ext jquery 简单比较
Apr 07 Javascript
javascript中对Attr(dom中属性)的操作示例讲解
Dec 02 Javascript
js生成验证码并直接在前端判断
May 15 Javascript
js带闹铃功能的倒计时代码
Sep 29 Javascript
Angular在一个页面中使用两个ng-app的方法(二)
Feb 20 Javascript
Cropper.js 实现裁剪图片并上传(PC端)
Aug 20 Javascript
使用cookie绕过验证码登录的实现代码
Oct 12 Javascript
Vue组件化开发思考
Feb 02 Javascript
学习node.js 断言的使用详解
Mar 18 Javascript
Node.js API详解之 Error模块用法实例分析
May 14 Javascript
原生js实现弹窗消息动画
Nov 20 Javascript
javascript动态改变img的src属性图片不显示的解决方法
Oct 20 #Javascript
javascript奇异的arguments分析
Oct 20 #Javascript
超越Jquery_01_isPlainObject分析与重构
Oct 20 #Javascript
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
Oct 20 #Javascript
理解Javascript_14_函数形式参数与arguments
Oct 20 #Javascript
理解Javascript_13_执行模型详解
Oct 20 #Javascript
用jquery与css打造个性化的单选框和复选框
Oct 20 #Javascript
You might like
php数据入库前清理 注意php intval与mysql的int取值范围不同
2010/12/12 PHP
PHP实现QQ空间自动回复说说的方法
2015/12/02 PHP
PHP实现简单登录界面
2019/10/23 PHP
jquery next nextAll nextUntil siblings的区别介绍
2013/10/05 Javascript
JS按字节截取字符长度实例
2013/11/20 Javascript
在jquery中的ajax方法怎样通过JSONP进行远程调用
2014/04/04 Javascript
jQuery的text()方法用法分析
2014/12/20 Javascript
jQuery中outerWidth()方法用法实例
2015/01/19 Javascript
javascript实现当前页导航激活的方法
2015/02/27 Javascript
js实现浮动在网页右侧的简洁QQ在线客服代码
2015/09/04 Javascript
JS实现图片预览的两种方式
2017/06/27 Javascript
详解vue的diff算法原理
2018/05/20 Javascript
微信小程序项目实践之九宫格实现及item跳转功能
2018/07/19 Javascript
vue实现自定义日期组件功能的实例代码
2018/11/06 Javascript
JavaScript数据结构与算法之二叉树添加/删除节点操作示例
2019/03/01 Javascript
JS控制只能输入数字并且最多允许小数点两位
2019/11/24 Javascript
js实现简单贪吃蛇游戏
2020/05/15 Javascript
[32:07]完美世界DOTA2联赛PWL S3 LBZS vs Rebirth 第一场 12.16
2020/12/17 DOTA
[52:03]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第三场 1月31日
2021/03/11 DOTA
Python Web开发模板引擎优缺点总结
2014/05/06 Python
Python入门篇之列表和元组
2014/10/17 Python
python保存数据到本地文件的方法
2018/06/23 Python
基于python实现计算两组数据P值
2020/07/10 Python
python 实现朴素贝叶斯算法的示例
2020/09/30 Python
用python写PDF转换器的实现
2020/10/29 Python
碧欧泉Biotherm加拿大官方网站:法国高端护肤品牌
2019/10/18 全球购物
大学生全国两会报告感想
2014/03/17 职场文书
园林技术专业求职信
2014/07/28 职场文书
党员个人公开承诺书
2014/08/29 职场文书
小学生迎国庆演讲稿
2014/09/05 职场文书
中秋节晚会开场白
2015/05/29 职场文书
大学生入党群众意见书
2015/06/02 职场文书
师范生教育见习总结
2015/06/23 职场文书
2019年七夕情人节浪漫祝福语大全!
2019/08/08 职场文书
Python包管理工具pip的15 个使用小技巧
2021/05/17 Python
浅析JavaScript中的变量提升
2022/06/01 Javascript