关于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 相关文章推荐
Web前端设计模式  制作漂亮的弹出层
Oct 29 Javascript
jQuery插件原来如此简单 jQuery插件的机制及实战
Feb 07 Javascript
使用jquery实现IE下按backspace相当于返回操作
Mar 18 Javascript
jQuery实现加入购物车飞入动画效果
Mar 14 Javascript
JS实现自动切换文字的导航效果代码
Aug 27 Javascript
Bootstrap栅格系统的使用和理解2
Dec 14 Javascript
微信小程序 解析网页内容详解及实例
Feb 22 Javascript
Vue 自定义动态组件实例详解
Mar 28 Javascript
详解在微信小程序的JS脚本中使用Promise来优化函数处理
Mar 06 Javascript
解决Vue @submit 提交后不刷新页面问题
Jul 18 Javascript
JS绘图Flot如何实现可选显示曲线图功能
Oct 16 Javascript
vue使用exif获取图片旋转,压缩的示例代码
Dec 11 Vue.js
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
预告映像公开!第1章续篇剧场版动画《Princess Principal Crown Handler》4月10日上映!
2020/03/06 日漫
PHP array操作10个小技巧分享
2011/06/23 PHP
用来解析.htpasswd文件的PHP类
2012/09/05 PHP
destoon常用的安全设置概述
2014/06/21 PHP
php检测文本的编码
2015/07/26 PHP
php生成图片验证码-附五种验证码
2015/08/19 PHP
Zend Framework教程之分发器Zend_Controller_Dispatcher用法详解
2016/03/07 PHP
javascript 哈希表(hashtable)的简单实现
2010/01/20 Javascript
ExtJs扩展之GroupPropertyGrid代码
2010/03/05 Javascript
Javascript 匿名函数及其代码模式原理
2010/03/19 Javascript
JQuery给元素添加/删除节点比如select
2013/04/02 Javascript
js函数setTimeout延迟执行的简单介绍
2013/07/17 Javascript
jquery实现动态菜单的实例代码
2013/11/28 Javascript
jquery增加和删除元素的方法
2015/01/14 Javascript
JavaScript中的getDay()方法使用详解
2015/06/09 Javascript
令按钮悬浮在(手机)页面底部的实现方法
2017/05/02 Javascript
兼容浏览器的js事件绑定函数(详解)
2017/05/09 Javascript
Vue页面骨架屏的实现方法
2018/05/22 Javascript
微信小程序methods中定义的方法互相调用的实例代码
2018/08/07 Javascript
vue+elementUI实现表格关键字筛选高亮
2020/10/26 Javascript
基于Electron实现桌面应用开发代码实例
2020/07/07 Javascript
Python socket C/S结构的聊天室应用实现
2014/11/30 Python
详解python string类型 bytes类型 bytearray类型
2017/12/16 Python
详谈Numpy中数组重塑、合并与拆分方法
2018/04/17 Python
TensorFlow实现简单卷积神经网络
2018/05/24 Python
解决Python中定时任务线程无法自动退出的问题
2019/02/18 Python
在Python中表示一个对象的方法
2019/06/25 Python
python根据完整路径获得盘名/路径名/文件名/文件扩展名的方法
2020/04/22 Python
解决Keras中CNN输入维度报错问题
2020/06/29 Python
利用python实现后端写网页(flask框架)
2021/02/28 Python
事业单位个人应聘自荐信
2013/09/21 职场文书
财务人员担保书
2014/05/13 职场文书
少先队活动总结
2014/08/29 职场文书
发工资啦!教你用Python实现邮箱自动群发工资条
2021/05/10 Python
Golang map映射的用法
2022/04/22 Golang
Flutter Navigator 实现路由传递参数
2022/04/22 Java/Android