# JS-This(一)
🐴
# 前言
今天来写一写JavaScript中的this,虽然this已经被讨论烂了,但是我们这里还是从两个角度去探索一下,这篇文章我们从多种情况来总结出this的指向,下一篇关于this的文章中我们从另一个角度来探讨一下this的指向问题。这篇文章只是总结了常见的this指向的问题,并没有从根源说起,如果想了解更多,可以看第二篇关于this的文章。
this其实就是执行上下文的一个属性,在javaScript中this时在进入上下文时确定的,并且在上下文运行期间一直不会发生变化。下面我们来看看this指向的多种情况。
# 全局中的this
全局中的this对于我们来说应该还是很好理解的,全局中的this, 指向的就是 window。
console.log(this) // 指向window
var a = 10;
console.log(this.a) // 10 this执行window
# 函数中的this
函数中的this相对于全局中的this来说比较难搞,我们需要考虑函数的执行上下文,因为this是在函数调用时来确定的,也就是说调用函数的方式不同会影响this的指向,下面我们来看看函数中的this,
// 全局中执行fun函数
function fun(){
console.log(this)
}
fun() // this 指向window
// 以原型的构造函数方式调用
fun.propotype.constructor() // this 指向fun.propotype对象
//对象中调用fun
var obj = {
fun:function(){
console.log(this)
}
}
obj.fun() // this 指向 obj对象
var f = obj.fun;
f()// this 指向 window对象
我们可以发现,函数作为对象的方法调用时,会指向调用该函数的对象(这么说不是很严谨,我们讨论的只是this的指向情况), 如果将对象的方法赋值给全局变量,那么在函数执行时,this会指向window
另外我们看看下面这种情况:
var obj = {
bar: function () {
console.log(this);
},
fun:function(){
function f(){
console.log(this)
}
f()
}
};
(obj.bar)(); // this 指向obj
(true&&obj.bar)(); // this 指向window
(obj.bar = obj.bar)(); // this 指向window
obj.fun(); // this 指向window
为了方便记忆我们可以这样确定this,首先括号()是组运算对this的确定没有影响,但是其他的赋值运算会对this造成影响,比如=、&&、||, 此时会将this值会是undefined,并最终指向window。所以针对上面的例子我们就可以得出
(obj.bar)()结果为this指向obj, 因为组运算对this的确定没有影响;(true&&obj.bar)()和(obj.bar = obj.bar)()的结果为this指向window,因为赋值运算会改变this指向;obj.fun()结果为this指向window,这种情况下,我们可以记住,函数执行后,内部函数执行时this的值会是undefined,并最终将会指向window,(虽然这么去理解是不正确的,但是为了更快的记住this的指向,只能这么干了。)
# 定时器中的this
setTimeout方法和setInterval方法是全局对象window的两个方法,在这两个方法触发的函数(不包含ES6箭头函数)中的this指向window
var foo = {
bar: function () {
setTimeout(function(){
console.log(this)
},2000)
},
fun:function(){
setInterval(function(){
console.log(this)
},2000)
},
};
foo.bar() // this 指向 window
foo.fun() // this 指向 window
# DOM事件中的this
DOM事件中绑定的函数中的this指向触发该事件的DOM元素。
<div id="test">
aaaaaaaaaaaaaae
</div>
<script>
var div = document.querySelector("#test")
div.onclick = function(){
console.log(this) // 指向id为test的元素
}
</script>
# ES6 中的this
在es6中讨论this 我们这里就不得不提箭头函数了, 和es5中,函数在执行时确定this不同,es6的箭头函数中根本没有自己的this,箭头函数中是继承自上级上下文中的this。
var foo = {
bar: function () {
setTimeout(function(){
console.log(this)
},2000)
},
fun:function(){
setTimeout(()=>{
console.log(this)
},2000)
},
};
foo.bar() // this 指向 window
foo.fun() // this 指向 foo
var newF = foo.fun;
newF() // this 指向 window
通过上面例子我们可以看到,定时器setTimeout触发函数中的this应该是指向window的,但是当在setTimeout中使用箭头函数时,因为箭头函数没有this,它的this是继承上级的上下文中的this的。
第二种情况我们可以看出,在执行foo.fun()时箭头函数中的this就是继承自foo.fun中的this, 当通过foo.fun()调用函数时,foo.fun中的this指向foo,所以箭头函数中的this指向foo对象
第三种情况通过newF()调用函数时,foo.fun中的this指向undefined,最终指向window上面我们也分析过,所以箭头函数中的this指向window
所以在确定箭头函数中的this时,我们只需要确定它上级的上下文中的this即可。
我们在来看看下面在DOM事件中箭头函数内的this
<div id="test">
aaaaaaaaaaaaaae
</div>
<script>
var div = document.querySelector("#test")
div.onclick = () =>{
console.log(this) // 指向 window
}
</script>
DOM事件中箭头函数内的this也不再指向触发事件的元素了,而是指向它的上级上下文中的this即window。
# 构造函数中的this
在构造函数中this还是很好确定的,在构造函数中this永远指向通过构造函数创建的对象。
function people(){
this.name = "king";
this.age = 52
}
var one = new People()
var two = new People()
上面在构造函数中的this会指向通过new创建出来的对象。第一种情况下people中的this指向 one对象,第二种情况下people中的this指向 two对象