JavaScript中的this到底是怎样的?
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的默认指向是全局对象。看下面代码: