深入理解JavaScript中this关键字的指向机制

作者:半夏时间:2026-10-25 11:38:53浏览:287

本文深入解析JavaScript中this关键字的指向逻辑。通过对比函数作为顶层调用、对象方法调用及嵌套函数返回等不同场景,阐明this始终指向当前执行函数的拥有者。文章详细讨论了函数Copy与Refer的区别,以及通过call、apply或变量引用解决嵌套函数this指向问题的方法,帮助开发者避免常见的上下文错误。

JavaScript this关键字详解

以下内容约70%源自http://www.quirksmode.org/js/this.html,其余30%为个人对this关键字的理解与总结。希望这些内容能对读者有所帮助。



首先,我们来看一个关于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指向

【函数的拥有者】


要解释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'的HTML对象。


JavaScript this关键字详解

显而易见,此时this指向了这个div元素。也就是说,test1()的拥有者变成了div这个HTML对象,或者说它变成了由div的onclick方法调用的函数。这种情况应该比较容易理解。


下面我们继续修改代码,只改动一处:


代码如下:

 
o.onclick = test1(); // 注意:这里加了个括号

将上面代码的最后一句改为上述形式后,点击div运行的结果为:'me', true


结果变回了与第一种情况相同,this重新指向了window。有人可能会感到困惑,认为这两者没有区别,但实际上是有区别的。这里涉及到函数的Copy(复制)和Refer(引用)的问题。



函数Copy与Refer的区别

【函数的Copy】


如果通过


代码如下:

 
o.onclick = test1;

这样的方式,实际上是将test1()这个函数Copy(复制)给了对象o的onclick属性。因此,test1的拥有者变成了o这个对象。


如果通过


代码如下:

 
o.onclick = test1();

这样的方式,本质上是指当获取到点击事件的处理句柄时,指引它去执行test1()函数。注意是“指引去执行”而不是“赋给它去执行”。test1()的拥有者没有改变,仍然是window。



【函数的Refer】


同上,如果我们通过内联HTML的方式将调用写入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实际上是建立了一个对doSomething的reference(引用),而不是Copy(复制)了这个函数。



通过call显式绑定this

【用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';
} 

这也是对象冒充最典型的方式。



嵌套函数中的this指向问题

【自由变量问题】


写了这么长,我们还是回到最开始的那个问题:


代码如下:

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

作者最新文章