关于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 相关文章推荐
js自带函数备忘 数组
Dec 29 Javascript
javascript图片相似度算法实现 js实现直方图和向量算法
Jan 14 Javascript
JavaScript实现SHA-1加密算法的方法
Mar 11 Javascript
解决angular的$http.post()提交数据时后台接收不到参数值问题的方法
Dec 10 Javascript
JS实现1000以内被3或5整除的数字之和
Feb 18 Javascript
基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
Jun 12 Javascript
你不知道的 javascript【推荐】
Jan 08 Javascript
解决微信小程序中转换时间格式IOS不兼容的问题
Feb 15 Javascript
Vue formData实现图片上传
Aug 20 Javascript
layui--select使用以及下拉框实现键盘选择的例子
Sep 24 Javascript
vue实现瀑布流组件滑动加载更多
Mar 10 Javascript
javascript实现电商放大镜效果
Nov 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实现的DES加密解密实例代码
2016/04/06 PHP
Joomla简单判断用户是否登录的方法
2016/05/04 PHP
浅析PHP中的 inet_pton 网络函数
2019/12/16 PHP
thinkphp框架实现路由重定义简化url访问地址的方法分析
2020/04/04 PHP
JavaScript面向对象之Prototypes和继承
2012/07/12 Javascript
form表单中去掉默认的enter键提交并绑定js方法实现代码
2013/04/01 Javascript
JavaScript实现复制功能各浏览器支持情况实测
2013/07/18 Javascript
Jquery设置attr的disabled属性控制某行显示或者隐藏
2014/09/25 Javascript
Javascript快速排序算法详解
2014/12/03 Javascript
Jquery解析json字符串及json数组的方法
2015/05/29 Javascript
jquery地址栏链接与a标签链接匹配之特效代码总结
2015/08/24 Javascript
Bootstrap每天必学之栅格系统(布局)
2015/11/25 Javascript
微信小程序  action-sheet详解及实例代码
2016/11/09 Javascript
js时间控件只显示年月
2017/01/08 Javascript
HTML5+jQuery实现搜索智能匹配功能
2017/03/24 jQuery
nodeJS实现路由功能实例代码
2017/06/08 NodeJs
jQuery实现仿京东防抖动菜单效果示例
2018/07/06 jQuery
layui+jquery支持IE8的表格分页方法
2019/09/28 jQuery
如何基于js判断浏览器版本
2020/02/20 Javascript
[54:56]DOTA2上海特级锦标赛主赛事日 - 5 总决赛Liquid VS Secret第三局
2016/03/06 DOTA
pandas 将list切分后存入DataFrame中的实例
2018/07/03 Python
Django密码系统实现过程详解
2019/07/19 Python
如何在Django配置文件里配置session链接
2019/08/06 Python
在pycharm中配置Anaconda以及pip源配置详解
2019/09/09 Python
Python中*args和**kwargs的区别详解
2019/09/17 Python
python爬虫开发之PyQuery模块详细使用方法与实例全解
2020/03/09 Python
彻底搞懂python 迭代器和生成器
2020/09/07 Python
python openCV自制绘画板
2020/10/27 Python
加拿大健康、婴儿和美容产品在线购物:Well.ca
2016/11/30 全球购物
Wallis官网:英国女装零售商
2020/01/21 全球购物
北京一家公司的.net开发工程师笔试题
2012/04/17 面试题
大学生职业生涯规划书范文
2014/01/04 职场文书
办公室人员先进事迹
2014/01/27 职场文书
幼儿园保教管理制度
2014/02/03 职场文书
食堂标语大全
2014/06/11 职场文书
十大最强火系宝可梦,喷火龙上榜,第一名有双火属性
2022/03/18 日漫