JS核心理论之《this、call、apply与bind》

355 阅读2分钟

this

this指向

在JavaScript中this可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式,this 绑定的对象即函数执行的上下文环境(context)。

记住规则:在ES5中,this 永远指向最后调用它的那个对象,判断this引用什么的唯一方法就是看使用this关键字的这个方法在哪里被调用的。

箭头函数的 this 始终指向函数定义时的 this,而非执行时。

我们通过以下例子来证明这一点:

var name = "window";
function a() {
    var name = "ben";
    console.log(this.name);          // window
    console.log("inner:" + this);    // inner: window
}
a(); 

原因是a的调用对象是window,相当于 window.a(), 所以this指向了window, this.name取的是全局变量的name。

而如果像下面这样调用,输出的就是局部变量的name。

var name = "window";
var a = {
    name: "ben",
    fn : function () {
        console.log(this.name);      // ben
    }
}
a.fn();

原因是fn函数的调用者是a, this指向的是a, this.name取的就是a.name。

再对上例做一下改变:

var name = "window";
var a = {
    fn : function () {
        console.log(this.name);      // undefined
    }
}
window.a.fn();

此时fn的最后调用者仍然是a,所以this指向a,而a没有局部变量name,所以输出undefined。

最后再做一下改变,我们发现输出又不同了。

var name = "window";
var a = {
    name: "ben",
    fn : function () {
        console.log(this.name);      // window
    }
}

var f = a.fn;
f();

原因是a.fn赋值给f变量,但并没有执行调用。而f()执行时调用者仍然是window,所以this最终指向了window。

改变this的指向的方法:

  • 使用 ES6 的箭头函数
  • 在函数内部使用 _this = this
  • 使用 apply、call、bind
  • new 实例化一个对象

call

  • 语法:func.call(thisArg, arg1, arg2, ...)
  • 定义:call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

示例:

var a ={
    name : "ben",
    fn : function (a,b) {
        console.log( a + b)
    }
}

var b = a.fn;
b.call(a,1,2)   //3

apply

  • 语法:func.apply(thisArg, [argsArray])
  • 定义:apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

示例:

var a ={
    name : "ben",
    fn : function (a,b) {
        console.log( a + b)
    }
}

var b = a.fn;
b.apply(a,[1,2])   //3

该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。

bind

  • 语法:func.apply(thisArg, [argsArray])
  • 定义:bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

示例:

var a ={
    name : "ben",
    fn : function (a,b) {
        console.log( a + b)
    }
}

var b = a.fn;
b.bind(a,1,2)()    //3

所以我们可以看出,bind 是创建一个新的函数,我们必须要手动去调用。 注意call、apply、bind的调用者都是function,包括构建函数。