35.箭头函数和普通函数区别

  • 普通函数/方法中的this, 谁调用就是谁
  • 箭头函数中的this, 是父作用域的this,不是调用者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let p = {
name: "lnj",
say: function () {
console.log(this); // {name: "lnj", say: ƒ}
},
// 因为没有将箭头函数放到其它的函数中,
// 所以箭头函数属于全局作用域

// 在JS中只有定义一个新的函数才会开启一个新的作用域
hi: () => {
console.log(this); // Window
}
}
p.say();
p.hi();
  • 定义一个函数会开启一个作用域,因为没有将箭头函数放到其它的函数中(只是将箭头函数放在了对象里面),所以箭头函数属于全局作用域,那么tihs就是Window 对象

  • 因为将箭头函数放到其它的函数中,所以箭头函数属于其它函数(当前的其它函数就是构造函数),既然箭头函数属于构造函数,所以箭头函数中的this就是构造函数的this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Person() {
this.name = "lnj";
this.say = function () {
console.log(this); // Person
}
// 因为将箭头函数放到其它的函数中,
//所以箭头函数属于其它函数(当前的其它函数就是构造函数)

// 既然箭头函数属于构造函数,
//所以箭头函数中的this就是构造函数的this
this.hi = () =>{
console.log(this); // Person
}
}
let p = new Person();
p.say();
p.hi();
  • 注意点: 箭头函数中的this永远都只看它所属的作用域的this,无法通过bind/call/apply来修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Person() {
this.name = "lnj";
this.say = function () {
console.log(this); // {name: "zs"}
}
this.hi = () =>{
console.log(this); // Person
}
}
let p = new Person();
p.say.call({name: "zs"});
// 注意点: 箭头函数中的this永远都只看它所属的作用域的this
// 无法通过bind/call/apply来修改
p.hi.call({name: "zs"});

下面看箭头函数可以解决的一个this指向问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var num = 0;
function Obj (){
this.num = 1,
this.getNum = function(){
console.log(this.num);
},
this.getNumLater = function(){
setTimeout(function(){
console.log(this.num);
}, 1000)
}
}
var obj = new Obj;
obj.getNum();//1  打印的是obj.num,值为1
obj.getNumLater()//0  打印的是window.num,值为0

解释下:setTimeout中函数内的this是指向了window对象,这是由于setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。

  • MDN上关于”this”的问题

    由setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致,这些代码中包含的 this 关键字在非严格模式会指向 window (或全局)对象,严格模式下为 undefined,这和所期望的this的值是不一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var num = 0;
var obj= {
num:1,
getNum:function(){
console.log(this.num);
},
getNumLater:function(){
console.log(this);
setTimeout(() => {
console.log(this.num);
}, 1000) //箭头函数中的this总是指向外层调用者,也就是Obj
}
}
obj.getNum();//1  打印的是obj.num,值为1
obj.getNumLater()//1  打印的是obj.num,值为1
  • 上面的代码将setTimeout放在了getNumLater函数里面,所以setTimeout的父作用域就是了getNumLater函数开启的作用域,作用域里面的this,谁调用getNumLater函数,this就指向谁,也就是obj