this是困惑JavaScript开发者的一大‘毒瘤’,在开发过程中,但凡用到this的时候,我们都会很头疼,那么这个this在JavaScript中到底是怎么样的?身为一个前端coder,这是一个避不开的话题。

经典代码

下面,我们先开看一段社区里面的经典的精华代码,看看它到底试图说明什么:

复制代码
function foo() {     var a = 2;     this.bar(); }  function bar() {     console.log(this.a);  }  foo();    // ReferenceError: a is not defined
复制代码

 

看了这一段代码,我们不由再想一下两个问题

this指向函数自身吗(×)?

如果this指向函数自身,foo函数中的this.bar()竟然神奇的调用成功了,这显然是不对的。这时候如果打印this,很明显this指向全局对象window。

this指向词法作用域吗(×)?

如果this指向词法作用域,那么为什么bar()会引发引用错误?很明显,this也并不指向词法作用域。

我想,社区经典代码,大概就是为了陈述我们经常会有的这两种错误的观念,那么,我们这时候不仅要思考了,this到底是什么?

为什么会出现this?

说明JavaScript为什么要用this之前,我们先看看下面代码:

复制代码
function printName(obj){     console.log(obj.name) }  var obj1 = {     name: 'obj1Name' }  var obj2 = {     name: 'obj2Name' }  printName(obj1);    // obj1NameprintName(obj2);    // obj2Name
复制代码

 

在这段代码中,如果要打印出某对象的name属性,那么就需要显示的将对象传递进入方法参数,那么如果不想要传递参数,有没有什么办法来实现这样的操作?

这个时候,this便应运而生了。看下面代码:

复制代码
function printName(){     console.log(this.name) }  var obj1 = {     name: 'obj1Name' }  var obj2 = {     name: 'obj2Name' }  printName.call(obj1);    // obj1NameprintName.call(obj2);    // obj2Name
复制代码

 

这就是this出现的原因,this出现的宗旨是想要在函数调用的时候隐式的传递对象引用,想要使得我们的代码看起来更优雅,但是this在JavaScript的引入真的完美做到我们想要的事情了吗?

不,并没有,最起码this的指向就让大多数前端开发者头疼不已,甚至用词法作用域的概念去避免(self = this or 箭头函数)。

this的特点

有上述描述,我们可以得出this的一些特点:

1、隐式传递对象引用,但并不能穿透作用域(经典代码的bar)

2、运行时调用才会产生this

3、this不指向函数自身,也不指向词法作用域

所以,this到底是什么?

当函数调用时,this在运行时绑定,而函数调用此时产生了执行上下文,执行上下文中包括了调用栈、参数信息等,当然也包括了this。this正是为了在运行时绑定而存在的。

那么,this的绑定又是怎么样的呢,或者说this到底是指向了什么?

this指向(绑定)

先说JavaScript的this避坑三连:

1、当函数作为对象的方法调用的时候,函数中this指向该对象(上述call调用代码)。

2、当函数被正常调用(全局作用域下),this指向window。(注意:严格模式指向undefined)。

3、this不会有函数穿透现象(箭头函数或者匿名函数除外)

在这里说说第三点的函数穿透,其实和作用域穿透是相同的概念。那么为什么箭头函数和匿名函数可以穿透到外层this呢?

因为箭头函数没有自己的执行上下文,而this又是执行上下文的一个属性,所以,箭头函数的this或者说在其中如果调用this的话,其实就是调用的箭头函数外层的this。

this默认指向

要说this默认指向,只看简单的一个普通函数调用即可,一般来说,this的默认指向是全局对象。看下面代码: