关于javascript中this关键字(翻译+自我理解)

 更新时间:2010年10月20日 12:12:32   作者:  
在传统面向对象语言中,this关键字是个很乖的小孩,从不乱跑,该是谁的就是谁的。可是在JavaScript中,我们发现它不那么乖,有时甚至把我们搞的晕头转向的。所以有必要对它稍微做个总结。
下文有大概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

显而易见,此时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对象,否则会指向这个函数的拥有者。

相关文章

  • js简单判断flash是否加载完成的方法

    js简单判断flash是否加载完成的方法

    这篇文章主要介绍了js简单判断flash是否加载完成的方法,通过PercentLoaded方法对flash的加载进行判断,具有一定参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • JS中的六种继承方式以及优缺点总结

    JS中的六种继承方式以及优缺点总结

    JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一,那么如何在JS中实现继承呢?下面这篇文章主要给大家介绍了关于JS中六种继承方式以及优缺点的相关资料,需要的朋友可以参考下
    2021-10-10
  • javascript实现瀑布流自适应遇到的问题及解决方案

    javascript实现瀑布流自适应遇到的问题及解决方案

    这篇文章主要介绍了javascript实现瀑布流自适应遇到的问题及解决方案,需要的朋友可以参考下
    2015-01-01
  • javascript中的return和闭包函数浅析

    javascript中的return和闭包函数浅析

    这篇文章主要介绍了javascript中的return和闭包函数浅析,至少可以让你搞懂那么多()是什么意思,需要的朋友可以参考下
    2014-06-06
  • js 原型对象和原型链理解

    js 原型对象和原型链理解

    本文主要介绍了js原型对象和原型链的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • JavaScript 事件查询综合

    JavaScript 事件查询综合

    比较全的 js事件,大家可以快速的掌握 js事件效果代码。
    2009-07-07
  • D3.js实现柱状图的方法详解

    D3.js实现柱状图的方法详解

    相信大家都知道数据可视化就是借助图形化的手段把生硬的数据生动化,以此来展示出数据想要表达的信息,而图表是最通常的一种数据可视化手段。可全靠自己纯手动编写各种图表实在是让人头疼,各种计算各种烦。现在就为大家介绍如何用D3.js来实现柱状图。
    2016-09-09
  • JavaScript中变量提升和函数提升实例详解

    JavaScript中变量提升和函数提升实例详解

    这篇文章主要给大家介绍了关于JavaScript中变量提升和函数提升的相关资料,以及JS变量提升和函数提升的顺序,文中给出了详细的介绍,需要的朋友可以参考下
    2021-07-07
  • javascript实现倒计时并弹窗提示特效

    javascript实现倒计时并弹窗提示特效

    倒计时的功能在我们做项目的时候会经常遇到,这里给大家分享的是个人编写的一个简易的效果代码,有需要的小伙伴可以参考下
    2015-06-06
  • 文字溢出实现溢出的部分再放入一个新生成的div中具体代码

    文字溢出实现溢出的部分再放入一个新生成的div中具体代码

    说文字溢出,如何实现溢出的文字放入一个新生成的div中,原理就是判断是否能在div里放下,如果不能,则在应该断开的地方,差入到新的div中
    2013-05-05

最新评论