关于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 相关文章推荐
用jquery实现学校的校历(asp.net+jquery ui 1.72)
Jan 01 Javascript
JS记录用户登录次数实现代码
Jan 15 Javascript
js实现分享到随页面滚动而滑动效果的方法
Apr 10 Javascript
js查看一个函数的执行时间实例代码
Sep 12 Javascript
快速掌握Node.js中setTimeout和setInterval的使用方法
Mar 21 Javascript
jQuery实现的超链接提示效果示例【附demo源码下载】
Sep 09 Javascript
Centos7 中 Node.js安装简单方法
Nov 02 Javascript
bootstrap table之通用方法( 时间控件,导出,动态下拉框, 表单验证 ,选中与获取信息)代码分享
Jan 24 Javascript
angularjs中回车键触发某一事件的方法
Apr 24 Javascript
浅谈Vue3.0之前你必须知道的TypeScript实战技巧
Sep 11 Javascript
JavaScript 如何计算文本的行数的实现
Sep 14 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
使用xampp搭建运行php虚拟主机的详细步骤
2015/10/21 PHP
PHP实现一个简单url路由功能实例
2016/11/05 PHP
PHP 信号管理知识整理汇总
2017/02/19 PHP
PHP使用正则表达式实现过滤非法字符串功能示例
2018/06/04 PHP
JQuery 文本框回车跳到下一个文本框示例代码
2013/08/30 Javascript
nodejs教程之入门
2014/11/21 NodeJs
jQuery UI插件自定义confirm确认框的方法
2015/03/20 Javascript
javascript实现淡蓝色的鼠标拖动选择框实例
2015/05/09 Javascript
在AngularJS中使用AJAX的方法
2015/06/17 Javascript
JS中BOM相关知识点总结(必看篇)
2016/11/22 Javascript
学习vue.js中class与style绑定
2016/12/03 Javascript
详解Vue自定义过滤器的实现
2017/01/10 Javascript
JavaScript纯色二维码变成彩色二维码
2020/07/23 Javascript
Angular中响应式表单的三种更新值方法详析
2017/08/22 Javascript
浅谈webpack打包生成的bundle.js文件过大的问题
2018/02/22 Javascript
jQuery实现通过方向键控制div块上下左右移动的方法【测试可用】
2018/04/26 jQuery
Vuerouter的beforeEach与afterEach钩子函数的区别
2018/12/26 Javascript
vue 动态组件(component :is) 和 dom元素限制(is)用法说明
2020/09/04 Javascript
WINDOWS 同时安装 python2 python3 后 pip 错误的解决方法
2017/03/16 Python
Python实现多进程共享数据的方法分析
2017/12/04 Python
python3 面向对象__类的内置属性与方法的实例代码
2018/11/09 Python
python 实现的发送邮件模板【普通邮件、带附件、带图片邮件】
2019/07/06 Python
python绘制无向图度分布曲线示例
2019/11/22 Python
Python 连接 MySQL 的几种方法
2020/09/09 Python
canvas实现圆形进度条动画的示例代码
2017/12/26 HTML / CSS
html5实现九宫格抽奖可固定抽中某项奖品
2020/06/15 HTML / CSS
MaBelle玛贝尔香港官网:香港钻饰连锁店
2019/09/09 全球购物
小学三八妇女节活动方案
2014/03/16 职场文书
租赁协议书范本
2014/04/22 职场文书
表彰大会策划方案
2014/05/13 职场文书
小学先进集体事迹材料
2014/05/31 职场文书
消防安全宣传口号
2014/06/10 职场文书
初中生活随笔
2015/08/15 职场文书
学习焦裕禄先进事迹心得体会
2016/01/23 职场文书
用CSS3画一个爱心
2021/04/27 HTML / CSS
Python中的套接字编程是什么?
2021/06/21 Python