普通函数与箭头函数this指向问题

一、普通函数

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
var a=5;  //全局变量
var obj={
a:2,
show:function(){
console.log(this.a);
}
}
obj.show(); //2
var obj2=obj;
obj2.a=8;
obj2.show(); //8
var obj3=obj.show;
obj3(); //5

发现

三次调用show方法,我们可以发现:

  • 当直接调用对象自己内的方法时,this指向调用show方法的对象即obj;
  • 而将obj赋给新对象obj2时,再调用show时this就指向调用者obj2
  • 将obj.show赋给一个新对象obj3,通过obj3调用show函数,通过obj3调用show函数,此时的this指向window;

普通函数this指向问题

再考虑一下下面的情况:

1
2
3
4
5
6
7
8
9
var obj4 = {
a : 1,
func: function(){
console.log(this.a); //1
setTimeout(
function(){console.log(this.a)},3000)
}
}
obj4.func(); //3秒后输出全局变量中的5

obj4.func()中this可得到当前对象中的a,而setTimeout中要执行的方法是属于 window 的 method,因此它的this指向还是window对象

普通函数中,内层函数不能从外层函数中继承this的值,在内层函数中,this会是window或者undefined(取决于是否使用严格模式),可以设置一个临时变量用来将外部的this值导入到内部函数中,另外就是在内部函数执行.bind(this)

解决方案

1、var that=this
1
2
3
4
5
6
7
8
9
var obj4 = {
a : 1,
func: function(){
var that=this;
setTimeout(
function(){console.log(that.a)},3000)
}
}
obj4.func(); //1
setTimeout语法
1
2
window.setTimeout(code,delay);
//setTimeout是Window对象的方法(可省略window)

setTimeout(匿名函数, time)这种形式下,匿名函数中的变量也需要根据上下文来判断,
前面的this.a毫无疑问是全局中的a,而有了that变量,因为func作用域使得window.setTimeout能获取到当前对象(而非window对象),故a为1

2、通过bind()来绑定this
1
2
3
4
5
6
7
8
9
var obj5 = {
a : 7,
func: function(){
console.log(this.a);
setTimeout(
function(){console.log(this.a)}.bind(this),3000)
}
}
obj5.func() //7

调用 匿名函数.bind(this) 会创建一个与该函数具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数(这里只有this),无论这个函数是如何被调用的。bind绑定的参数只生效一次。


二、箭头函数

ES6标准新增了一种新的函数:Arrow Function(箭头函数)。

箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式

  • ++只包含一个表达式,连{ … }和return都省略掉了。++
  • ++还有一种可以包含多条语句,这时候就不能省略{ … }和return++

箭头函数中的this始终指向其父级作用域中的this,任何方法都改变不了其指向

栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var obj6= {
a : 101,
func:()=>{
console.log(this.a)
},
func1:()=>{
var b=()=>this.a
console.log(b())
},
func2:function(){
var b=()=>this.a
console.log(b())
},
}
obj6.func() //全局变量5
obj6.func1(); //5
obj6.func2() //101

分析

obj6.func()中的this会指向父级作用域的this也就是与obj6有相同的this指向,为window

对于方法,普通函数中的this总是指向它的调用者,所以obj6.func2()中的this指向为obj6的指向,所以a为101


三、两者差异

箭头函数和普通函数相比,有以下几点差异:

  1. 箭头函数没有 this,它会从自己的作用域链的上一层继承 this(因此无法使用 apply / call / bind 进行绑定 this 值

  2. 函数体内的 this对象,就是定义时所在的对象,而不是使用时所在的对象。

  3. 不可以使用 arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

  4. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

  5. 不可以使用 new 命令,因为

  • 没有自己的 this,无法调用 call,apply。
  • 没有 prototype 属性 ,即指向 undefined;

四、参考资料

https://www.jianshu.com/p/e5fe25edd78a
https://www.jianshu.com/p/acbd5a9b0211
https://www.liaoxuefeng.com/wiki/1022910821149312/1031549578462080

请我喝杯咖啡吧~

支付宝
微信