关于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 相关文章推荐
在视频前插入广告
Nov 20 Javascript
基于Jquery与WebMethod投票功能实现代码
Jan 19 Javascript
jquery.Ajax()方法调用Asp.Net后台的方法解析
Feb 13 Javascript
jquery实现的图片点击滚动效果
Apr 29 Javascript
Node.js中创建和管理外部进程详解
Aug 16 Javascript
自定义函数实现IE7与IE8不兼容js中trim函数的问题
Feb 03 Javascript
JS中的eval 为什么加括号
Apr 13 Javascript
AngularJS指令详解及示例代码
Aug 16 Javascript
详解用原生JavaScript实现jQuery的某些简单功能
Dec 19 Javascript
vue-cli和v-charts实现可视化图表过程解析
Oct 08 Javascript
Vue+Vuex实现自动登录的知识点详解
Mar 04 Javascript
ajax请求前端跨域问题原因及解决方案
Oct 16 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 读取大文件的X行到Y行内容的实现代码
2013/06/24 PHP
ThinkPHP自动完成中使用函数与回调方法实例
2014/11/29 PHP
浅析PHP中的i++与++i的区别及效率
2016/06/15 PHP
js 代码集(学习js的朋友可以看下)
2009/07/22 Javascript
JS正则中的RegExp对象对象
2012/11/07 Javascript
js关于字符长度限制的问题示例探讨
2014/01/24 Javascript
js运动动画的八个知识点
2015/03/12 Javascript
jquery动态切换背景图片的简单实现方法
2016/05/14 Javascript
Jquery和Js获得元素标签名称的方法总结
2016/10/08 Javascript
使用ReactJS实现tab页切换、菜单栏切换、手风琴切换和进度条效果
2016/10/17 Javascript
详解Angular Reactive Form 表单验证
2017/07/06 Javascript
protractor的安装与基本使用教程
2017/07/07 Javascript
获取layer.open弹出层的返回值方法
2018/08/20 Javascript
Vue-router 切换组件页面时进入进出动画方法
2018/09/01 Javascript
[jQuery] 事件和动画详解
2019/03/05 jQuery
JavaScript的垃圾回收机制与内存管理
2020/08/06 Javascript
python实现域名系统(DNS)正向查询的方法
2016/04/19 Python
Python编程之微信推送模板消息功能示例
2017/08/21 Python
3个用于数据科学的顶级Python库
2018/09/29 Python
对numpy中向量式三目运算符详解
2018/10/31 Python
Python使用post及get方式提交数据的实例
2019/01/24 Python
python+gdal+遥感图像拼接(mosaic)的实例
2020/03/10 Python
Python猴子补丁Monkey Patch用法实例解析
2020/03/23 Python
python爬虫分布式获取数据的实例方法
2020/11/26 Python
详解使用python爬取抖音app视频(appium可以操控手机)
2021/01/26 Python
总结30个CSS3选择器
2017/04/13 HTML / CSS
美味咖啡的顶级烘焙师:Cafe Britt
2018/03/15 全球购物
英语故事演讲稿
2014/04/29 职场文书
汉语言文学专业求职信
2014/06/19 职场文书
2014年医务科工作总结
2014/12/18 职场文书
2015年学生资助工作总结
2015/05/25 职场文书
灵魂歌王观后感
2015/06/17 职场文书
MySQL库表名大小写的选择
2021/06/05 MySQL
能用CSS实现的就不要麻烦JavaScript了
2021/10/05 HTML / CSS
OpenCV实现普通阈值
2021/11/17 Java/Android
Python可变与不可变数据和深拷贝与浅拷贝
2022/04/06 Python