JavaScript中的this详解
初探this
this关键字是JavaScript中最复杂的机制之一,掌握了它就掌握了进入JavaScript的魔法,它值得我们付出大量时间去学习。
学习this的第一步时明白this既不是指向函数自身也不是指向函数的词法作用域(变量或函数的可访问范围),this实际上实在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
什么是this
当一个函数被调用时,会创建一个活动记录(执行上下文)。这个记录包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息,this就是这个记录的一个属性,会在函数执行的过程中用到。
本文除了node和浏览器中的this这一章外,其他章节的运行环境都是浏览器下。
除特殊说明,本文代码都是在严格模式下执行的。
一般场景中的this
(1)先来看一个简单的
function foo() {
} console.log( this.a );
var a = 2;
foo(); //?
运行结果为2,这里的函数foo是在全局作用域中被调用的,相当于是全局对象调用了函数,所以函数中的this指向全局对象,this.a被解析成了window.a,即3。
(2)再来看看稍微复杂一点的
function foo() {
console.log( this.a );
}
var a = 2;
var obj = {
a: 3,
foo: foo
};
obj.foo(); //?
运行结果为3,这里的函数foo是被obj对象所调用,所以函数中的this指向obj,this.a被解析成了obj.a,即3。
(3)将上面代码稍微变化一下
function foo() {
console.log( this.a );
}
var a = 2;
var obj = {
a: 3,
foo: foo
};
var obj1=obj.foo;
obj1() //?
这时运行结果为2,为什么呢?这里相当于先进行了赋值操作,将obj.foo赋给obj1,实际的执行在下一步,所以调用位置又到了window中,this.a被解析成window.a,即2。
闭包中的this
var name = "The Window";
var object = {
name: "My object",
getNameFunc: function() {
return function () {
return this.name;
}
}
}
console.log(object.getNameFunc()()) //?
运行结果为The Window,以上代码先创建了一个全局变量name,又创建一个包含name属性的对象,该对象还包含一个方法——getNameFunc(),它返回一个匿名函数,而匿名函数又返回this.name。因此调用object.getNameFunc()()直接返回一个字符串。
那为什么匿名函数没有取得其包含作用域的this对象呢?
首先,有这样一个结论:匿名函数的执行环境具有全局性。
每个函数在被调用时都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远无法直接访问到外部函数中的这两个变量。
我们可以换种方式理解,将最后一步拆分成两步:
var obj1= object.getNameFunc();
obj1();
首先将对象中的函数赋给obj1,然后执行obj1(),这里的函数obj1是在全局作用域中被调用的,所以指向window。
不过我们可以将外部作用域中的this保存在闭包可以访问到的变量里