关于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调用WebServices的方法和4个实例
May 06 Javascript
js四舍五入数学函数round使用实例
May 09 Javascript
JavaScript生成二维码图片小结
Dec 27 Javascript
JavaScript学习笔记之数组去重
Mar 23 Javascript
js遍历json的key和value的实例
Jan 22 Javascript
jQuery实现弹窗居中效果类似alert()
Feb 27 Javascript
快速使用node.js进行web开发详解
Apr 26 Javascript
通过jquery.cookie.js实现记住用户名、密码登录功能
Jun 20 jQuery
angularjs结合html5实现拖拽功能
Jun 25 Javascript
JS选取DOM元素常见操作方法实例分析
Dec 10 Javascript
vue实现标签云效果的方法详解
Aug 28 Javascript
基于Vue实现微前端的示例代码
Apr 24 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
mysql时区问题
2008/03/26 PHP
PHP中ini_set和ini_get函数的用法小结
2014/02/18 PHP
destoon在360浏览器下出现用户被强行注销的解决方法
2014/06/26 PHP
php中Ctype函数用法详解
2014/12/09 PHP
关于IFRAME 自适应高度的研究
2006/07/20 Javascript
基于逻辑运算的简单权限系统(实现) JS 版
2007/03/24 Javascript
Prototype 学习 工具函数学习($A方法)
2009/07/12 Javascript
jQuery的live()方法对hover事件的处理示例
2014/02/27 Javascript
scrollWidth,clientWidth,offsetWidth的区别
2015/01/13 Javascript
JS动态遍历json中所有键值对的方法(不知道属性名的情况)
2016/12/28 Javascript
VUE中使用Vue-resource完成交互
2017/07/21 Javascript
JavaScript基础心法 数据类型
2018/03/05 Javascript
关于Angularjs中跨域设置白名单问题
2018/04/17 Javascript
JS实现根据指定值删除数组中的元素操作示例
2018/08/02 Javascript
在小程序中使用canvas的方法示例
2018/09/17 Javascript
js实现黑白div块画空心的图形
2018/12/13 Javascript
vue axios重复点击取消上一次请求封装的方法
2019/06/19 Javascript
angular8和ngrx8结合使用的步骤介绍
2019/12/01 Javascript
vue页面加载时的进度条功能(实例代码)
2020/01/13 Javascript
Openlayers学习之地图比例尺控件
2020/09/28 Javascript
python解析xml文件操作实例
2014/10/05 Python
django 解决manage.py migrate无效的问题
2018/05/27 Python
解决pyinstaller打包exe文件出现命令窗口一闪而过的问题
2018/10/31 Python
python批量从es取数据的方法(文档数超过10000)
2018/12/27 Python
Python面向对象程序设计OOP入门教程【类,实例,继承,重载等】
2019/01/05 Python
Python sqlite3查询操作过程解析
2020/02/20 Python
Python基于pyecharts实现关联图绘制
2020/03/27 Python
Python HTMLTestRunner测试报告view按钮失效解决方案
2020/05/25 Python
几个解决兼容IE6\7\8不支持html5标签的几个方法
2013/01/07 HTML / CSS
html5唤醒APP小记
2019/03/27 HTML / CSS
init进程的作用
2012/04/12 面试题
美国留学经济担保书
2014/05/20 职场文书
先进个人评语大全
2015/01/04 职场文书
邀请函样本
2015/02/02 职场文书
2015初中团支部工作总结
2015/07/21 职场文书
浅谈Python中的函数(def)及参数传递操作
2021/05/25 Python