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); // obj1Name
printName(obj2); // obj2Name
在这段代码中,如果要打印出某对象的name属性,那么就需要显示的将对象传递进入方法参数,那么如果不想要传递参数,有没有什么办法来实现这样的操作?
这个时候,this便应运而生了。看下面代码:
function printName(){
console.log(this.name)
}
var obj1 = {
name: 'obj1Name'
}
var obj2 = {
name: 'obj2Name'
}
printName.call(obj1); // obj1Name
printName.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的默认指向是全局对象。看下面代码:
var obj = {
name: 'objName',
printThis: function(){
console.log(this);
function innerFunc() {
console.log(this);
}
innerFunc();
}
}
obj.printThis();
这段代码中,我们执行代码,会发现,innerFunc的this打印出来的竟然是全局对象window(严格模式下,undefined),同时,这一段代码也印证了,我们obj调用函数时候,外层函数的this指向的是obj,并且没有this指向穿透现象。
显式this
那么有什么办法显式让对象调用this呢?(最上面的call)
看下面代码:
var obj = {
name: 'objName',
printThis: function(){
console.log(this);
var self = this;
function innerFunc() {
console.log(self);
}
innerFunc();
}
}
obj.printThis();
这一段代码,毫无疑问是对this默认指向的代码的修复(通过self避免,并非修改this指向,inner中this依旧指向全局对象)
箭头函数,和self避免的方式差不多,因为箭头函数没有执行上下文,它内部的this相当于是外部函数的this。
所以,如果是应用self避免,和箭头函数,我们相当于是撇开了this问题,是用词法作用域来避免我们不熟悉的东西,如果针对到this,我们依旧感觉到有些头疼。
那么,这时候,就需要显式执行this了。还是上述代码,做如下修改:
var obj = {
name: 'objName',
printThis: function(){
console.log(this);
function innerFunc() {
console.log(this);
}
innerFunc.call(obj); // 显式绑定this
}
}
obj.printThis();
这个时候,我们打印出来的两个this也就完全一致,都是obj对象,因为在这里我们用call来显式绑定了this。
除了call,我们还可以用bind和apply来实现如此效果。
总结
this在运行时产生,率属于函数上下文的一个属性,this的指向不一而定,是在函数调用时根据上下文来确定,也可以利用显式调用的call、apply、bind方式来修改this指向。
this是个不可避免的问题,当我们用箭头函数和self避免的时候,也要思考一下this的指向,以免混淆了this和词法作用域的概念。
You stated it wonderfully! canadian pharmacies that are legit
Beneficial write ups. Appreciate it. cymbalta 60 mg
Incredible many of beneficial material. tamsulosin hydrochloride
Nicely put. Thanks a lot! canadian pharmacies-24h
Thank you. Ample posts!
cbd vape oil
Thanks a lot, Fantastic information. Where To Buy Tretinoin Gel 01
You reported this wonderfully! phenergan generic
With thanks, Ample content.
canadian pharmacies online
Great posts. Thank you. does viagra really work
Fantastic stuff, Thanks. allopurinol 300