引言
在实际开发过程中,JavaScript的this还是比较常见的,但是由于分不清楚this的指向,导致出现很多难以理解的bug。本文就从JavaScript执行上下文
角度来说明白this,希望再也不担心this带来的问题了。
为什么出现this
对于陌生的事情,了解其背后的原因非常有助于理解。在对象内部的方法使用对象内部的属性是非常常见的需求,但是JavaScript并不支持,因此JavaScript提出this机制
来解决作用域机制的缺陷。
this是什么
之前文章提到过执行上下文中包含了变量环境、词法环境、外部环境,其实还有一个this。this是和执行上下文绑定的,每个执行上下文都有一个this。
所以this根据执行上下文的不同分为三种:全局执行上下文
中的this、函数
的this和eval
中的this。
- 全局执行上下文:this指向window对象(非严格模式)
- 函数执行上下文:分4种情况
- 默认情况:this指向window对象
function foo(){
console.log(this); //window
}
foo()
- 通过函数的call/apply/bind方法:this指向绑定的对象
let bar = {
myName : "hi",
test1 : 1
}
function foo(){
this.myName = "hello"
}
foo.call(bar)
console.log(bar) // hi
console.log(myName) //undefined
- 通过对象调用:this指向该对象
var myObj = {
name : "hello",
showThis: function(){
console.log(this)
}
}
myObj.showThis()
其实是因为JavaScript引擎在执行myObj.showThis()时转化为了 myObj.showThis.call(myObj),再来看个例子
var myObj = {
name : "hi",
showThis: function(){
this.name = "hello"
console.log(this) // window对象
}
}
var foo = myObj.showThis;
foo()
通过例子可知:
- 在全局环境中调用函数,函数内部的this指向全局变量window
- 通过一个对象来调用其内部的一个方法,this指向对象本身
- 通过构造函数:指向新对象
function CreateObj(){
this.name = "hi"
}
var myObj = new CreateObj()
当执行new CreateObj时,JavaScript引擎做了如下三件事:
- 创建一个空对象tempOjb;
- 调用CreateObj.call方法,并将tempObj作为call方法的参数,this就指向了tempObj
- 执行crateobj函数,返回tempObj对象
- eval函数上下文:
eval
只在被直接调用时,this指向才是当前作用域
\
this有哪些缺陷
我们都知道this在使用过程中存在不少坑,下面说几个比较常见的:
- 嵌套函数中的this不会从外层函数中继承
举个例子
var myObj = {
name : "hi",
showThis: function(){
console.log(this); // myObj
function bar(){console.log(this)} //window
bar()
}
}
myObj.showThis()
通过上面例子可知this没有作用域限制。
解决方法:
- 再showThis函数中声明一个变量self用来保存this,本质上把this机制转化为作用域机制。
- 使用es6中的箭头函数
- 普通函数中的this默认指向全局对象window 解决方法:
- 通过call方法显示调用
- 设置JavaScript的严格模式
总结
本文通过上下文角度说明了JavaScript中的this机制,可见明白了来龙去脉,this指向也没那么难理解了。