关于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 相关文章推荐
关于__defineGetter__ 和__defineSetter__的说明
May 12 Javascript
fmt:formatDate的输出格式详解
Jan 09 Javascript
node.js中的fs.fsync方法使用说明
Dec 15 Javascript
js正则匹配出所有图片及图片地址src的方法
Jun 08 Javascript
AngularJS 使用$sce控制代码安全检查
Jan 05 Javascript
JavaScript html5 canvas绘制时钟效果(二)
Mar 27 Javascript
【经典源码收藏】基于jQuery的项目常见函数封装集合
Jun 07 Javascript
Reactjs实现通用分页组件的实例代码
Jan 19 Javascript
JS+Ajax实现百度智能搜索框
Aug 04 Javascript
利用HBuilder打包前端开发webapp为apk的方法
Nov 13 Javascript
微信小程序购物车、父子组件传值及calc的注意事项总结
Nov 14 Javascript
js console.log打印对象时属性缺失的解决方法
May 23 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脚本的10个技巧(3)
2006/10/09 PHP
ThinkPHP自动转义存储富文本编辑器内容导致读取出错的解决方法
2014/08/08 PHP
php时间戳格式化显示友好的时间函数分享
2014/10/21 PHP
详谈php静态方法及普通方法的区别
2016/10/04 PHP
SAE实时日志接口SDK用法示例
2016/10/09 PHP
javaScript 利用闭包模拟对象的私有属性
2011/12/29 Javascript
使用FlexiGrid实现Extjs表格效果方法分享
2014/12/16 Javascript
详解AngularJS控制器的使用
2016/03/09 Javascript
Bootstrap每天必学之响应式导航、轮播图
2016/04/25 Javascript
基于jquery实现ajax无刷新评论
2020/08/19 Javascript
纯JS实现可拖拽表单的简单实例
2016/09/02 Javascript
jQuery层次选择器用法示例
2016/09/09 Javascript
Vue.js 2.0 和 React、Augular等其他前端框架大比拼
2016/10/08 Javascript
vue.js中mint-ui框架的使用方法
2017/05/12 Javascript
在vue中更换字体,本地存储字体非引用在线字体库的方法
2018/09/28 Javascript
详解Vue demo实现商品列表的展示
2019/05/07 Javascript
JavaScript如何获取一个元素的样式信息
2019/07/29 Javascript
node事件循环和process模块实例分析
2020/02/14 Javascript
vue-admin-template配置快捷导航的代码(标签导航栏)
2020/09/04 Javascript
[01:08]DOTA2次级职业联赛 - Shield战队宣传片
2014/12/01 DOTA
[03:12]完美世界DOTA2联赛PWL DAY9集锦
2020/11/10 DOTA
进一步了解Python中的XML 工具
2015/04/13 Python
Python代码解决RenderView窗口not found问题
2016/08/28 Python
Python爬豆瓣电影实例
2018/02/23 Python
解决Pycharm出现的部分快捷键无效问题
2018/10/22 Python
Python 隐藏输入密码时屏幕回显的实例
2019/02/19 Python
python支付宝支付示例详解
2019/08/22 Python
python上传时包含boundary时的解决方法
2020/04/08 Python
药学专业大专生的自我评价
2013/12/12 职场文书
会计应聘求职信范文
2013/12/17 职场文书
演讲稿怎么写
2014/01/07 职场文书
设计师个人求职信范文
2014/02/02 职场文书
群众路线教育实践活动批评与自我批评
2014/09/15 职场文书
先进个人推荐材料
2014/12/29 职场文书
2015年六一儿童节活动方案
2015/05/05 职场文书
在职证明格式样本
2015/06/15 职场文书