JS中的this指向一直扰乱着我们,很多时候觉得自己写的东西没有bug但是执行后的结构总是跟自己预想的不一样,这个时候我们就该想想是不是我们的对象的this出现了问题。接下来我们一步一步地分析一下this的问题。
1.非箭头函数中this在函数定义的时候是确定不了的,只有在函数执行的时候才能确定this到底指向谁,this指向最终调用它的对象
在js中this主要分为以下几种情况
- 在全局作用域下
var name = "Eric" console.log(this) //输出window console.log(this.name)//输出"Eric"
非严格模式全局作用域下this永远指向window,如果是严格模式,this是undefined
-
在函数作用域下
var name = "Eric" function show(){ console.log(this);//输出window console.log(this.name);//输出"Eric" } show();
此种情况下show()调用的时候我们可以看做window.show(),show()的执行环境是window,也就相当于函数show()被window调用所以this指向window。但是在严格模式下this依然是undefined
-
在对象里面
var obj = { name : "Eric"; show:function(){ console.log(this); console.log(this.name); } } obj.show() //obj //"Eric"
此情况下函数show()是通过obj这个对象调用的,所以函数show()里面的this指向obj.这里有个经典的问题,如下:
var obj = { show:function(){ console.log(this); function fn(){ console.log(this); } fn(); } } obj.show() //obj //window /*此时fn()里 的this会指向window....完了,看懵了,为什么这个this会指向window呢?因为fn()在show()函数中,但是并没用通过obj或者show直接调用,只是自己调用,因此,fn()就是一个全局函数,所以fn()中的this会指向window*/
为了彻底理解这个this我们再举个例子
var obj = { name : "Eric", show:function(){ console.log(this); } } var outer = obj.show; outer()//window
这里的this指向window.这是因为将obj里面的show赋值给outer的时候并没有执行,只是吧obj里面的函数show给了outer,而outer是在window里创建的相当于
var outer = function(){ console.log(this) } outer()//window
这就和第二种情况一样了,outer是通过window直接调用的,所以this指向window,还有一种情况
var obj = { name : "Eric", show:function(){ console.log(this); return function(){ console.log(this) } } } obj.show()() //obj //window
这种情况函数show()里面返回了一个匿名函数,在函数show()里面并没有调用,只是定义,真正的调用时在window下调用的,写两个括号可能不太清楚,我们可以这样写var outer = obj.show();这里只执行了show里面的console.log并没有执行返回的匿名函数,outer()这样才是表示window下调用,所以第二个this指向window
同理想setTimeout这种函数如下var obj = { name:"Eric", show:function(){ console.log(this) setTimeout(function(){ console.log(this) },1000) } } obj.show() //obj //window
setTimeout中的function我们可以理解为是一个callback,即:
function callback(){} setTimeout(callback,1000)
它的伪代码可以这样写
function setTimeout(fn,delay) { // 等待delay 毫秒 fn(); // <-- 调用位置! }
他是直接调用fn(),前面没有给任何对象绑定在一起,所以根据JavaScript的规则,它属于默认绑定,自然就是window了
-
构造函数中的this,我们先来看例子
function Object(){ this.name = 12; this.show= function(){ console.log(this) //Object:{a:12,show:f()} } } var obj = new Object() obj.show()//obj
(1) 要明白构造函数的this指向,我们需要明白调用构造函数经历的步骤:
a。创建一个新对象。
b。将构造函数的作用域赋给新对象(因此this就指向了这个新对象)。
c。执行构造函数中的代码(为这个新对象添加属性)。
d。返回新对象。
-
箭头函数中的this
箭头函数的this是在定义函数时绑定的,不是在执行过程中绑定的。简单的说,函数在定义时,this就继承了定义函数的对象。
var obj = { fun1:function(){ console.log(this) }, fun2:function(){ console.log(this) setTimeout(function(){ console.log(this) },1000) }, fun3:function(){ console.log(this) setTimeout(()=>{ console.log(this) },1000) } } obj.fun1()//obj obj.fun2()//obj window obj.fun3()//obj obj
通过fun2和fun3的对比我们发现箭头函数的this是和和他上一级函数的this保持一致的,箭头函数中是没有this的,所谓的箭头函数的this是通过继承来的,继承的就是它上一级的函数中的this