面试宝典之箭头函数中的this
当面试官问ES6你都了解哪些啊?你大概率会说,箭头函数。那么面试官接着问,箭头函数跟function有什么区别啊?然后你又自信满满的说this指向的不同。那么面试官又问,那请说明一个this指向都有哪些不同?这时部分同学会对this的概念表达很模糊,下面就来详细说下箭头函数this指向的问题~
1.function和箭头函数的this指向有哪些不同?
要了解箭头函数中的this,先看function中的this优点以及不足,再来看箭头函数的设计会看的比较清晰。
function中的this指向的是使用时所在的对象,而箭头函数中的this指向定义时所在的对象,这点非常重要,举个例子~
function fn(){
console.log(this);
};
fn();复制请问打印出来的this在浏览器中显示什么?
答:应该显示的是fn外层的对象,因为使用者为fn外层的对象,如果fn处在最顶层,那么在浏览器中应该显示window对象,在node.js中应该显示global对象,也就是现在他们的顶级作用域对象。如果在fn的外层是一个function对象,那么就指向function的this。听起来可能有点晕,不过没关系,多举例子就明白了~
再举个例子
birth = 1994;
var obj = {
birth: 2000,
getAge: function () {
console.log(this.birth);
}
};
obj.getAge();
var a = obj.getAge;//2000
a();//1994复制那么这两个调用为什么会一个输出2000一个输出1994呢?还是之前的答案,因为function中的this指向的是使用者的对象,第一个使用者为obj对象,所以this当然指向obj。第二个呢,上方birth没有写var 自动赋值给了顶级作用域(当然不推荐大家这样赋值哈,就是做个例子^_^)然后当调用a()的时候其实是顶级对象在调用它,当然this指的是顶级作用域。
2.function这种动态的this指向哪些弊端能用箭头函数解决?
所以在某些场景下会使用function就找不到需要的this,比如
class Test {
constructor() {
this.birth = 10;
}
submit(){
$.ajax({
type: "POST",//方法类型
dataType: "json",//预期服务器返回的数据类型
url: "xxxxx" ,//url
data: "xxxxx",
success: function (result) {
console.log(this.birth);//undefined
},
error : function() {}
});
}
}
let test = new Test();
test.submit();//undef复制这时传统的解决方案是这样:把this赋值给一个变量。
class Test {
constructor() {
this.birth = 10;
}
submit(){
let self = this;
$.ajax({
type: "POST",
dataType: "json",
url: "xxxxx" ,//url
data: "xxxxx",
success: function (result) {
console.log(self.birth);//10
},
error : function() {}
});
}
}
let test = new Test();
test.submit();//undefined复制
通过this赋值给一个变量,然后再通过变量访问。
这时箭头函数的第一个优势就出来了,因为箭头函数中的this指向的是定义时的对象这时箭头函数定义时的对象为 Test类的实例对象,也就是test对象,所以this能找到birth属性。
...
success: (result)=> {
console.log(this.birth);//10
},
...复制
3.普通函数动态this指向优势有哪些?
当然function函数这种动态的this指向有他的好处,就是可以自由的指向对象,比如js中call或者apply方法可以动态指定function中的this对象,如果没有call或者apply方法,则是指向调用者的对象。
birth = 1994;
var obj = {
birth: 2000,
getAge: function () {
console.log(this.birth);
}
};
var obj2 = {
birth: 2018;
};
var a = obj.getAge;
a();//1994
a.call(obj);//2000
a.call(obj2);//2018复制
如果使用箭头函数会这样,看下面例子
birth = 1994;
var obj = {
birth: 2000,
getAge: ()=> {
console.log(this.birth);
}
};
var obj2 = {
birth: 2018;
};
var a = obj.getAge;
a();//1994
a.call(obj);//1994
a.call(obj2);//1994复制
在浏览器中定义箭头函数的的调用对象为window,所以不用使用什么方法,它的this对象指向的都是window对象,所以call或者apply对箭头函数不起作用,因为箭头函数一旦被调用者定义就不会改变。
3.箭头函数中的this的使用场景
下面的例子是function和箭头函数混合使用,先用function函数在确定this指向,然后查看下面箭头函数this指向。
function foo() {
setTimeout(() => {
console.log(this.id);
}, 100);
}
id = 21;
foo.call({ id: 12 });//12复制
外层foo函数确认指向的是一个{ id:12}对象,然后它下面的箭头函数作为setTimeout的回调函数,其定义时上下文的this对象,也就是foo函数的this,所以foo函数的this指向哪里就是哪里,如果把箭头函数变为普通函数,那么虽然定义时调用者为foo,但是实际100ms后真正使用这个函数的时window对象。如下~
function foo() {
setTimeout(function (){
console.log(this.id);
}, 100);
}
id = 21;
foo.call({ id: 12 });//21复制
所以在箭头函数中this指向的这个特性非常在回调函数中的应用。
4.扩展-箭头函数跟普通函数的区别都有哪些?
函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象。当对箭头函数使用call()和apply()方法时对函数内的this没有影响。不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
箭头函数没有原型属性。
注意:当写代码中使用的都是同一个变量时,如果拿不到值的话,那么记得看一下当前的this调用,是在普通函数中使用还是箭头函数中使用,要想在多个方法中都同时对一个变量进行操作,那么就在箭头函数中使用,()=>{console.log(this.pipColData)}。一定要用箭头函数,当时我保存拿不到值,就是this的指向不对,纠结了好久,所以总结了这些,希望以后大家也不要到再犯这个错误了。