this详解

js中this的调用方式主要有以下几种。

普通函数调用

在这种情况下,属于全局性的调用,this就代表全局对象window。

// this指向的就是全局window,该方式相当于定义一个全局变量
function a () {
    this.x = 1
    console.log(this.x)
}
a(); // 1

// 将变量移到外面,调用结果一样
var x = 1
function a () {
    console.log(this.x)
}
a(); // 1

作为方法调用

该种方法通过对象方法调用,这时this指向这个对象的上级,且具体指向由调用时来决定。

// 这里的this指向该对象,所以输出2
var x = 0;
var a = {
    x: 1;
    showX: function () {
        console.log(this.name);
    }
}
a.showX(); // 1

// 这里将a.showX赋值给全局变量,所以此时的this指向window
var m = a.showX;
m(); // 0

//虽然showX方法在a中定义,但是调用时候却是在b中调用,因此this指向b
var a = {
    x: 1,
    showX: function () {
        console.log(this.x);
    }
}
var b = {
    x: 2,
    showX: a.showX
}
b.showX(); // 2

作为构造函数调用

function A (x) {
    this.x = x;
}
var a = new A();
a.x(1); // 1

call/apply方法调用

使用call/apply方法可以改变this的指向

var x = 0;
var a = {
    x: 1,
    showX: function () {
        console.log(this.name);
    }
}
a.showX.call(); // 0

bind方法调用

setTimeout/setInterval/匿名函数执行的时候,this默认指向window对象,除非手动改变this的指向。在《javascript高级程序设计》当中,写到:“超时调用的代码(setTimeout)都是在全局作用域中执行的,因此函数中的this的值,在非严格模式下是指向window对象,在严格模式下是指向undefined”

// 这里的setTimeout函数,相当于window.setTimeout(),此时this指向全局
var x = 0;
function A (x) {
    this.x = x;
    this.showX = function () {
        setTimeout(function () {
            console.log(this.x);
        }, 50)
    }
}
var a = new A(1);
a.showX(); // 0

// 通过bind()方法,绑定setTimeout里面的匿名函数this一直指向A
var x = 0;
function A (x) {
    this.x = x;
    this.showX = function () {
        setTimeout(function () {
            console.log(this.x);
        }.bind(this), 50)
    }
}
var a = new A(1);
a.showX(); // 1

箭头函数

es6里面this指向固定化,始终指向外部对象,因为箭头函数没有this,因此它自身不能进行new实例化,同时也不能使用call, apply, bind等方法来改变this的指向

   function Timer() {
        this.seconds = 0;
        setInterval( () => this.seconds ++, 1000);
    } 

    var timer = new Timer();

    setTimeout( () => console.log(timer.seconds), 3100);

    // 3

    在构造函数内部的setInterval()内的回调函数,this始终指向实例化的对象,并获取实例化对象的seconds的属性,每1s这个属性的值都会增加1。否则最后在3s后执行setTimeOut()函数执行后输出的是0