javascript 中 this 的指向

this 的指向

this 的指向大致可以分为以下4种

  1. 作为对象的方法调用
  2. 作为普通函数调用
  3. 构造器调用
  4. Function.prototype.call 或 Function.prototype.apply 调用

当函数作为对象的方法被调用时,this指向该对象:

1
2
3
4
5
6
7
8
var obj = {
a: 1,
getA: function(){
alert(this == obj); //输出:true
alert(this.a); //输出:1
}
}
obj.getA();

作为普通函数调用

当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的this总是指向全局对象。在浏览器的 javascript 里,这个全局变量是 window 对象。

1
2
3
4
5
6
window.name = 'globalName';
var getName = function(){
return this.name;
}

console.log(getName()); //输出:globalName

或者

1
2
3
4
5
6
7
8
9
10
window.name = 'globalName';
var myObj = {
name: 'sven',
getName: function(){
return this.name;
}
}

var getName = myObj.getName;
console.log(getName()); //globalName

有时候我们会遇到一些困扰,比如在 div 节点的时间函数内部,有一个局部的 callback 方法,callback方法被作为普通的函数调用时,callback内部的this指向了window,但我们往往是想让它指向该div节点

1
2
3
4
5
6
7
8
9
10
window.id = 'window';

document.getElementById('div1').onclick = function(){
alert(this.id); // tihs为该 div 节点,this.id = div1
//var that = this; //保存引用 that.id 指向 div1
var callback = function(){
alert(that.id); //window
}
callback();
}

此时需用 that 保存下 div 节点的引用。

在 es5 的 strict 模式下,这种情况下的 this 已经被规定为不会指向全局对象,而是 undefined;

1
2
3
4
5
6
function func(){
'use strict'
alert(this); //undefined
}

func();

构造器调用

当用 new 运算符调用函数时,该函数总会返回一个对象,通常情况下,构造器里的 this 就指向返回的这个对象。

1
2
3
4
5
6
var myClass = function(){
this.name = 'sven';
}

var obj = new myClass();
alert(obj.name); //sven

但用 new 调用构造器时,还需要注意一个问题,如果构造器显式地返回了一个 object 类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的 this:

1
2
3
4
5
6
7
8
9
var myClass = function(){
this.name = 'sven';
return {
name: 'anne'
}
}

var obj = new myClass();
alert(obj.name); //anne

如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成上述问题。

1
2
3
4
5
6
7
var myClass = function(){
this.name = 'sven';
return 'anne';
}

var obj = new myClass();
alert(obj.name); //sven

Function.prototype.call 或 Function.prototype.apply 调用

这两个方法可以动态地改变传入函数的 this

1
2
3
4
5
6
7
8
9
10
11
12
13
var obj1 = {
name: 'sven',
getName: function(){
return this.name;
}
}

var obj2 = {
name: 'anne',
}

console.log(obj1.getName());
console.log(obj1.getName.call(obj2));