this是什么

214 阅读2分钟

当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方式,传入的参数等信息。this 就是这个记录的一个属性,会在函数执行的过程中用到。

每个函数的 this 是在调用时被绑定的,完全取决于函数的调用位置(也就是函数的调用方法)。

1、调用位置

首先,我们需要理解调用位置: 就是函数在代码中被调用的位置(注意,不是申明的位置)。只有自信分析到调用的位置,才能知道这个 this 到底引用的是什么。

还有一个调用栈的概念:就是为了到达当前执行位置所调用的所有函数。 我们关心的调用位置就在当前正在执行的函数的前一个调用中。

我们来看一个栗子:

function baz(){
    //当前调用栈是: baz
    //因此,当前调用位置是全局作用域
    
    console.log("baz");
    bar();  //  <--  bar的调用位置
}
​
function bar(){
    //当前调用栈:baz -> bar
    //因此,当前调用位置在 baz 中
    
    console.log("bar");
    foo();  //  <--  foo的调用位置
}
​
function foo(){
    //当前调用栈:baz -> bar -> foo
    //因此,当前调用位置在 bar 中
    
    console.log("foo");
}
​
baz();  //  <--baz  的调用位置

2、this 的绑定规则

默认绑定,隐式绑定,显式绑定, new绑定。首先找到调用位置,然后判断需要应用这四条规则中的哪一条。

首先,我们需要了解这四条规则,以及多条规则都适用时,他们的优先级该如何排列。

今天我们先来学习一下 默认绑定

最常用的函数调用规则:独立函数调用。

可以把这条规则看着是无法应用其他规则时的默认规则。思考一下下面代码:

function foo(){ 
    console.log(this.a);
}
​
var a = 3;
foo();  //3

生命在全局作用域中的变量(比如 var a = 3 ),就是全局对象的一个同盟属性。他们本质上就是同一个东西,并不是复制得到的。

该例中,函数调用时应用了默认绑定,因此,this 指向的是全局对象。

那么我们怎么知道这里应用的是*默认绑定 *呢?

在代码中,foo() 是直接使用不带任何修饰的函数引用进行调用的,因此只能使用 默认绑定

需要注意的是:如果使用严格模式,则不能将全局对象用于默认绑定,因此,this 会绑定undefined。

function foo(){ 
    "use strict";
    console.log(this.a);
}
​
var a = 3;
foo();  // TypeError this is undefined

这里有一个微妙但是非常重要的细节:虽然 this 的绑定规则完全取决于调用位置,但是只有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;在严格模式下调用 foo() 则不影响默认绑定。

function foo(){ 
    console.log(this.a);
}
​
var a = 3;
(fnction (){
    "use strict";
    foo();  //3
})(); 

\