原文地址:深入理解闭包(三)——确定this指向
我们在前面说过,在执行上下文创建过程中做了三件事:创建变量对象,生成作用域链,确定this指向。今天我们就来探讨一下this指向的问题。首先先回顾一下我们执行上下文的生命周期图:
执行上下文是函数被调用时创建的,创建过程包括确定this指向,所以this的指向是在函数被调用时确定的。
我们知道,this对象是在运行时基于函数的执行环境绑定的:在全局环境中,this指向window,当函数被作为某个对象的方法调用时,this指向那个对象。不过实际情况中往往没有那么好判断,今天我们就来梳理一下。
全局对象中的this
在全局环境下,this永远指向window。
console.log(this); //window
函数中的this
this指向调用这个函数的对象。
var a = 10;
function test() {
var a = 20;
console.log(this.a);
}
test(); //10
由于函数test是被全局对象(window)调用的,因此函数内部的this指向window。
var a = 20;
var obj = {
a: 10,
b:this.a,
fn: function () {
return this.a;
}
}
console.log(obj.fn()); //10
console.log(obj.b); //20
由于函数fn是被对象obj调用的,因此函数fn内部的this指向对象obj。
另外,由于obj不是个函数,不适合上面的规则,我们要单独讨论,如果obj对象在全局创建,那么obj里面的this指向window。
构造函数
构造函数和其他函数的唯一区别,就是他们的调用方式不同。任何函数,只要通过new
操作符来调用,那它就可以作为构造函数,调用时经历以下四个步骤:
- 创建一个新对象;
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象。
function Test() {
this.a = 1;
console.log(this.a); //1
}
var fun = new Test();
console.log(fun.a); //1
创建新对象new Test()
后,this指向这个新对象,然后为这个新对象添加属性a = 1
,再执行console.log(this.a)
,此时输出的就是刚添加的a值。返回这个新对象传递给了实例对象fun
,此时this指向了实例fun
,因此fun.a
也为1。
函数用call或apply调用
我们可以利用call或apply手动设置this的指向,这两个方法的第一个参数都是this将要指向的对象,后面的参数,都是向将要执行的函数传递参数。其中call以一个一个的形式传递,apply以数组的形式传递,这是他们唯一的不同。
var obj = {
num: 10
}
function test(a, b) {
console.log(this.num + a + b);
}
test(20,30); //NaN
test.call(obj, 20, 30); // 60
test.apply(obj, [20, 30]); // 60
这个例子很容易理解,本来调用test函数this指向全局对象,是无法访问到obj对象中的num的,但是利用call和apply方法将this指向了obj对象,所以可以顺利输出。
以上就是我目前知道的关于this指向的几种情况,以后可能会再补充。