关于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 相关文章推荐
Extjs列表详细信息窗口新建后自动加载解决方法
Apr 02 Javascript
jquery 新手学习常见问题解决方法
Apr 18 Javascript
js获取php变量的实现代码
Aug 10 Javascript
在firefox和Chrome下关闭浏览器窗口无效的解决方法
Jan 16 Javascript
动态加载js的方法汇总
Feb 13 Javascript
jquery滚动加载数据的方法
Mar 09 Javascript
10条建议帮助你创建更好的jQuery插件
May 18 Javascript
纯javascript模仿微信打飞机小游戏
Aug 20 Javascript
Javascript原型链的原理详解
Jan 05 Javascript
react-redux中connect的装饰器用法@connect详解
Jan 13 Javascript
集成vue到jquery/bootstrap项目的方法
Feb 10 jQuery
vue js秒转天数小时分钟秒的实例代码
Aug 08 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 单引号与双引号的区别
2009/11/24 PHP
php gd2 上传图片/文字水印/图片水印/等比例缩略图/实现代码
2010/05/15 PHP
php生成短域名函数
2015/03/23 PHP
PHP实现事件机制实例分析
2015/06/26 PHP
PHP实现适用于自定义的验证码类
2016/06/15 PHP
用正则xmlHttp实现的偷(转)
2007/01/22 Javascript
jquery重复提交请求的原因浅析
2014/05/23 Javascript
在JavaScript中处理数组之reverse()方法的使用
2015/06/09 Javascript
js实现Select头像选择实时预览代码
2015/08/17 Javascript
jQuery动态加载css文件实现方法
2016/06/15 Javascript
javascript实现瀑布流动态加载图片原理
2016/08/12 Javascript
AngularJs  E2E Testing 详解
2016/09/02 Javascript
微信小程序 JS动态修改样式的实现代码
2017/02/10 Javascript
微信小程序实现拖拽 image 触摸事件监听的实例
2017/08/17 Javascript
在vue中使用SockJS实现webSocket通信的过程
2018/08/29 Javascript
javascript实现图片轮播代码
2019/07/09 Javascript
Servlet返回的数据js解析2种方法
2019/12/12 Javascript
Vue中axios拦截器如何单独配置token
2019/12/27 Javascript
Vue组件为什么data必须是一个函数
2020/06/11 Javascript
Python的Flask框架及Nginx实现静态文件访问限制功能
2016/06/27 Python
Python 模板引擎的注入问题分析
2017/01/01 Python
python中字符串类型json操作的注意事项
2017/05/02 Python
python 实现调用子文件下的模块方法
2018/12/07 Python
使用python 将图片复制到系统剪贴中
2019/12/13 Python
使用python实现飞机大战游戏
2020/03/23 Python
在Python3.74+PyCharm2020.1 x64中安装使用Kivy的详细教程
2020/08/07 Python
收集的22款给力的HTML5和CSS3帮助工具
2012/09/14 HTML / CSS
香港时装购物网站:ZALORA香港
2017/04/23 全球购物
Lookfantastic香港官网:英国知名美妆购物网站
2018/06/19 全球购物
法定授权委托证明书
2014/09/27 职场文书
2015年公共机构节能宣传周活动总结
2015/03/26 职场文书
在校证明模板
2015/06/17 职场文书
二婚主持词
2015/06/30 职场文书
四十年同学聚会致辞
2015/07/28 职场文书
《绝招》教学反思
2016/02/20 职场文书
jQuery class属性操作addClass()与removeClass()、hasClass()、toggleClass()
2021/03/31 jQuery