this的指向,是在函数被调用的时候确定的。
在ES5中this一直是很神奇的东西,因为如果不是很理解的话,this是真的会弄崩心态的(所以ES6的箭头函数真是很友好了)
最近也有在准备笔试,想把基础夯实,所以今天写一篇关于this指向的blog。
在开头,我们说this的指向是在函数被调用的时候确定的。这是因为this的指向在执行上下文被创建时确定的。就是说这段this代码,他运行在不同的环境,this就能指向不同的对象。
先来看一个例子
var x = 10;
var obj = {
x: 20
}
function demo () {
console.log(this.x);
}
fn(); // 10
fn.call(obj); // 20
第一个fn()中,fn()是独立调用的,我调用我自己,所以this指向自己为undefine,但是是为非严格模式,this指向undefined时会自动指向全局变量。而第二个fn.call(obj)可以理解为,fn让obj作为它的调用者,所以this指向调用者obj,所以最后输出为20。
再来看一个例子:
'use strict';
var a = 20;
function foo () {
var a = 1;
var obj = {
a: 10,
c: this.a + 20,
fn: function () {
return this.a;
}
}
return obj.fn;
}
console.log(foo());
console.log(window.foo());
现在按照上面的思路来推一下
由于foo()是独立调用的,那么它之中的this是指向undefine的,所以第一句console.log(foo())报错:Cannot read property 'a' of undefined.
而第二句,foo()有一个调用者是window,所以this全部指向window,最后是全局的a:20 + 20 输出40.
现在对独立调用和被调用应该有了一个大致的理解,对于this的指向也有了初步的认识。
我们再看这一个例子:
var a = 20;
function foo1(){
var obj = {
a: 10,
getA: function () {
return this.a;
}
}
return obj.getA();
}
console.log(foo1());//10
function foo2(){
var obj = {
a: 10,
getA: function () {
return this.a;
}
}
return obj.getA;
}
console.log(foo2()());//20
这个例子说明,我们必须弄明白真正的调用者是谁,foo1中,是直接return this.a,this指向了getA的调用者obj。而foo2(),相当于有一个 var tmp = obj.getA()的操作,函数的调用真正的调用者是tmp自己,这个是独立调用,指向Undefine.
在ES6中,由于箭头函数的存在,让this由动态变成了静态
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
对于这个ES6入门中的例子,我们可以看到,如果是普通的函数的话,由于setTimeout是异步的,等待0.1s后运行匿名函数打印id时,this的执行上下文已经不是foo,而是在全局中独立调用,指向undefined。 这里我一开始觉得是应该是独立调用,指向undefined,只是因为没有用严格模式,后来我查了一下,应该不是因为this的执行上下文,而是setTimeout中的this指针会默认指向window