关于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和Js中,如何让ajax执行完后再继续往下执行
Jul 09 Javascript
jqueyr判断checkbox组的选中(示例代码)
Nov 08 Javascript
js实现下拉框选择要显示图片的方法
Feb 16 Javascript
JavaScript中的getTimezoneOffset()方法使用详解
Jun 10 Javascript
跟我学习javascript的undefined与null
Nov 17 Javascript
手机Web APP如何实现分享多平台功能
Aug 19 Javascript
CheckBox多选取值及判断CheckBox选中是否为空的实例
Oct 31 Javascript
webpack多页面开发实践
Dec 18 Javascript
vue.js 实现输入框动态添加功能
Jun 25 Javascript
node中的cookie的具体使用
Sep 13 Javascript
微信JS-SDK updateAppMessageShareData安卓不能自定义分享详解
Mar 29 Javascript
layui自定义验证,用ajax查询后台是否有重复数据,form.verify的例子
Sep 06 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继承的一个应用
2011/09/06 PHP
PHP中使用匿名函数操作数据库的例子
2014/11/17 PHP
php随机生成数字字母组合的方法
2015/03/18 PHP
PHP实现批量检测网站是否能够正常打开的方法
2016/08/23 PHP
用js实现控制内容的向上向下滚动效果
2007/06/26 Javascript
表单项的name命名为submit、reset引起的问题
2007/12/22 Javascript
使用jscript实现二进制读写脚本代码
2008/06/09 Javascript
使用隐藏的new来创建对象
2011/03/29 Javascript
jQuery父级以及同级元素查找介绍
2013/09/04 Javascript
详解AngularJS中的依赖注入机制
2015/06/17 Javascript
基于javascript实现动态时钟效果
2020/08/18 Javascript
jQuery+ajax简单实现文件上传的方法
2016/06/03 Javascript
Node.js的Koa框架上手及MySQL操作指南
2016/06/13 Javascript
js中window.open的参数及注意注意事项
2016/07/06 Javascript
jQuery日程管理控件glDatePicker用法详解
2017/03/29 jQuery
angularjs2中父子组件的数据传递的实例代码
2017/07/05 Javascript
js原生代码实现轮播图的实例讲解
2017/07/28 Javascript
bootstrap-table组合表头的实现方法
2017/09/07 Javascript
ajax前台后台跨域请求处理方式
2018/02/08 Javascript
基于JavaScript实现瀑布流布局
2018/08/15 Javascript
浅谈redux以及react-redux简单实现
2018/08/28 Javascript
Vue 监听列表item渲染事件方法
2018/09/06 Javascript
[07:26]2015国际邀请赛第二日TOP10集锦
2015/08/06 DOTA
python读取html中指定元素生成excle文件示例
2014/04/03 Python
Python实现字符串的逆序 C++字符串逆序算法
2020/05/28 Python
flask的orm框架SQLAlchemy查询实现解析
2019/12/12 Python
python topk()函数求最大和最小值实例
2020/04/02 Python
详解Python 中的容器 collections
2020/08/17 Python
python如何遍历指定路径下所有文件(按按照时间区间检索)
2020/09/14 Python
Python tempfile模块生成临时文件和临时目录
2020/09/30 Python
Johnston & Murphy官网: 约翰斯顿·墨菲牛津总统鞋
2018/01/09 全球购物
软件测试面试题
2014/01/05 面试题
院领导写的就业推荐信
2014/03/09 职场文书
商铺门面租房协议书
2014/10/21 职场文书
老公婚前保证书
2015/02/28 职场文书
幼儿园小班班务总结
2015/08/03 职场文书