前言
在学习JavaScript的时候,this是经常出问题的地方。
在像Java,PHP这些编程语言里面,this仅仅是类方法中当前对象的一个实例,它不能在方法外部被调用,这样一个简单的法则并不会造成任何疑惑。
而在 JavaScript 中,this 是指当前函数中正在执行的上下文环境,理解 this 关键字的关键在于理解各种不同的函数调用以及它是如何影响上下文环境的。
首先记住这一句话:this 是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
this 的四种绑定规则
在 JavaScript 中,影响 this 指向的绑定规则有四种:
- 默认绑定
- 隐式绑定
- 显式绑定
- new 绑定
一、默认绑定(普通函数调用)
这是最直接的一种方式,就是不加任何的修饰符直接调用函数。
在默认绑定中,上下文执行环境是全局对象,例子:

使用 var 声明的变量 a,被绑定到全局对象中,如果是浏览器,则是在 window 对象,相当于window.func()。
foo() 调用时,引用了默认绑定,this 指向了全局对象。
二、隐式绑定(作为对象的方法调用)
这种情况会发生在调用位置存在「上下文对象」的情况,如:


三、显式绑定(bind / apply / call 调用)
这种就是使用 Function.prototype 中的三个方法 call(), apply(), bind() 了,
这三个函数,都可以改变函数的 this 指向到指定的对象。
不同之处在于,call() 和 apply() 是立即执行函数,并且接受的参数的形式不同:
- call(this, arg1, arg2, ...)
- apply(this, [arg1, arg2, ...])
而 bind() 则是创建一个新的包装函数,并且返回,而不是立刻执行。 - bind(this, arg1, arg2, ...)
apply() 接收参数的形式,有助于函数嵌套函数的时候,把 arguments 变量传递到下一层函数中。更对的参考bind,apply,call的理解以及手写
demo3.png 上面代码中, foo() 内部的 this 遵循默认绑定规则,绑定到全局变量中。
而 bar() 在调用的时候,调用了 apply() 函数,把 this 绑定到了一个新的对象中 {a: 2},而且原封不动的接收 foo() 接收的函数。
四、new 绑定(构造函数的调用)
在 JavaScript 中,所有的函数都可以被 new 调用,这时候这个函数一般会被称为「构造函数」,实际上并不存在所谓「构造函数」,更确切的理解应该是对于函数的「构造调用」。关于new的解释请参考JavaScript中的new()做了些什么

使用new来调用函数时,会自动执行下面的操作:
1.创建一个全新的对象。
2.这个对象会被执行[ [原型] ]连接。
3.这个新对象会被绑定到函数调用的this.
4.返回这个新对象。
五、箭头函数
箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值。如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this;否则,this 的值会被设置为 undefined。

这时 this 不是指向 thisHandler,而是 Window。
优先级

所以优先级顺序为:
「new 绑定」 > 「显式绑定」 > 「隐式绑定」 > 「默认绑定。」
总结
this 并不是在编写的时候绑定的,而是在运行时绑定的。它的上下文取决于函数调用时的各种条件。实际上在非严格模式下,如果方法有直接调用者,那么this指向的是这个直接调用者,在没有直接调用者(比如回调函数)的情况下this指向的是全局对象(浏览器中是window,node中是global)。
网友评论