我相信很多前端开发人员都跟我一样,提起this
, 都能说出很多爱恨情仇...
误区
首先我们说说this
的很多错误理解版本:
函数本身
这是初学者最容易走进的误区,如果我说this
不是指函数本身,他们会觉得自己那么多年英文白学了,学习this
,首先要走出这个误区。
注意: 很多时候我们确实需要在一个方法中获得这个方法本身的引用, 比如递归调用。有以下两种情况可供参考:
- 实名函数
public static int sum(int num){
if(1 == num){
return 1;
} else {
return num + sum(num - 1);
}
};
sum()
可以直接通过它的名字sum
在方法中获得方法本身的引用。
- 匿名函数
setTimeout(function(){
if(some condition)
setTimeout(arguments.callee, 0); //arguments.callee is deprecated and may be removed.
}, 0);
函数的主人
this
既然不是函数自己,那是什么呢?会不会是这个方法的所属对象?答案显然是no。
this
究竟指什么?
在解释这个问题之前,我们先了解一个概念:
call-site
In programming, a call site of a function or subroutine is the location (line of code) where the function is called (or may be called, through dynamic dispatch). A call site is where zero or more arguments are passed to the function, and zero or more return values are received. (from wikipedia)
根据维基百科定义,call-site指函数被调用的位置,并且在这个位置,函数获得了它的context。看懂了吧,this
仍然可以从字面上理解为这里,但不是方法里,而是方法被调用的位置这里,因为它是在方法调用时被定义的,而不是方法声明时被定义的。
博主:说到这里大家应该知道this
指什么了吧,那本文可以结束了...
读者:什么,这就完了,太抽象了,可以讲点具体的吗???
哈哈,想知道this
指什么,只需要分清楚以下几种情况:
独立函数调用
this
指全局的Window对象或者undefined
var simpleFunction= function () {
console.log(this);//严格模式下 undefined, 非严格模式下[object Window]
};
simpleFunction();//call-site
特定上下文调用
this
指方法所属的对象
var myObject = {}
myObject .simpleFunction= function () {
console.log(this);// myObject
};
myObject .simpleFunction();
请区别以下代码:
var myObject = {}
myObject .simpleFunction= function () {
console.log(this);// myObject
};
var simpleFunction2 = myObject .simpleFunction;
//获得了simpleFunction的引用,此时simpleFunction2与myObject没有任何关系
simpleFunction2();//[object Window]
绑定上下文调用
通过apply()
call()
bind()
传入期望的this
。
var myObject = {}
myObject .simpleFunction= function () {
console.log(this);//[object Window]
};
myObject .simpleFunction.call(this);
很多时候,以上3种方法可以帮我解决this
混乱的情况。在下面的代码中,介绍一种叫硬绑定模式:
function foo(something) {
console.log( this.a, something );
return this.a + something;
}
var obj = {
a: 2
};
var bar = foo.bind( obj );
var b = bar( 3 ); // 2 3
new 绑定
设想以下代码即将运行:
new simpleFunction(arguments)
紧接着,会发生以下事情:
- 一个继承自simpleFunction.prototype的全新对象被创建
- simpleFunction被传入给定参数,然后调用,
this
被绑定到新创建的对象上(new
是一种方法的调用形式,而不是类声明)。 - 方法的返回值变成
new
表达式的值,如果没有返回值,就用第1步创建的对象代替
由上可以看出,new
只是一种调用方式,这种调用方式可以指定方法运行时的this
。
引用MDN提供的例子:
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
var mycar = new Car('Eagle', 'Talon TSi', 1993);
以上代码创建了一个mycar对象,对象有make
model
year
3个属性,值分别为'Eagle'
'Talon TSi'
1993
。
其他情况
setTimeout
setTimeout
是自行调用,而且是在全局环境下调用,因此往往会丢失掉期望的this
var obj = {};
obj.myMethod = function () {
console.log(this); // obj
setTimeout(function () {
console.log(this); // [object Window]
}, 100);
};
可以使用bind
setTimeout(function () {
console.log(this);
}.bind(this, 100));
也可以跳出域的限制
var that = this;
console.log(this); // this = obj
setTimeout(function () {
console.log(that); // that (this) = obj
}, 100);
某些特殊情况下this
已被绑定到好特定上下文。
forEach
function foo(el) {
console.log( el, this.id );
}
var obj = {
id: "awesome"
};
[1, 2, 3].forEach( foo, obj ); // 1 awesome 2 awesome 3 awesome
Javascript内建函数帮我们实现了foo.call(obj, index)
。
addEventListener
var element = document.querySelector('.elem');
var someMethod = function () {
console.log(this)//<div class="elem"></div>;
};
element.addEventListener('click', someMethod, false);
什么情况下我们会使用this
?
未完待续
参考: