this与JavaScript中的四种调用模式

this是什么

—In most languages, ‘this’ is a reference to the current object instantiated by the class. In JavaScript, ‘this’ normally refers to the object which ‘owns’ the method, but it depends on how a function is called.
—大多语言中,’this’代表由类实例化的当前对象。在JavaScript中,’this’通常表示’拥有’方法的对象,但具体取决于一个函数被调用的方式。

方法调用模式

当一个函数被保存为对象的一个属性并调用该方法时,this被绑定至该对象。即使用”obj.method”形式

```js
var val = "outer";
var methodCall = {
    val: "inner",
    printVal: function(){
        console.log(this.val);
    }
}
methodCall.printVal();  //"inner"
```

构造器调用模式

类似面向对象语言中对象的概念,使用new后,this被绑定至该实例。

```js
var val = "outer";
function methodCall(){
    this.val = "inner";
}
methodCall.prototype = {
    printVal: function(){
        console.log(this.val);
    }
}
var a = new methodCall();
a.printVal();   //"inner"
```

函数调用模式

函数未作为对象的属性时,其当作一个正常函数来调用,此时this被绑定至全局对象。

```js
var val = "outer";
function methodCall(){
    this.val = "inner";
}
methodCall.prototype = {
    printVal: function(){
        var that = this;
        var innerPrintVal = function(){
            console.log(that.val);
            console.log(this.val)
        }
        innerPrintVal();
    }
}
var a = new methodCall();
a.printVal();
```

打印结果为

```js
inner
outer
```
  • a.printVal调用printVal的方式为构造器调用模式,这时的this被绑定到a的作用域。将其赋给that,此时that就代表了a的作用域。
  • a.printVal调用innerPrintVal的方式为函数调用模式,这时的this被绑定到全局作用域。

注意,在a.printVal中,this是被绑定在a的作用域上的。但是在调用innerPrintVal时,this在该函数中被再一次绑定到全局作用域了。因此在innerPrintVal中调用console.log(this.val)打印的结果为”outer”

apply/call模式

手动指定this的值

```js
var val = "outer";

function printVal(){
    console.log(this.val);
}
function methodCall(){
    this.val = "inner";
}
methodCall.prototype = {
    printVal: function(){
        console.log(this.val);
    }
}
var a = new methodCall();
a.printVal();               //"inner"
a.printVal.call(a);         //"inner"
printVal.call(a);           //"inner"

printVal();                 //"outer"
printVal.apply(window);     //"outer"
a.printVal.apply(window);   //"outer"
```

输出结果为:

```js
inner
inner
inner
outer
outer
outer
```

可以看出,无论是采用构造器调用模式的a.printVal或是采用函数调用模式的printVal,this均会被apply/call绑定为手动指定的值