揭秘箭头函数的底层原理

1,943 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

箭头函数的基本使用与注意点

基本用法

箭头函数是es6里新增加的语法糖;
在es6之前我们定义返还函数可以通过以下方式来实现:

var fun=function(arg){
return arg;
}
console.log(fun('123'));  //123  

在es6中我们通过箭头函数让其变得更加的简单,如下:

var fun=arg=>arg;
console.log(fun('123'));  //123  

箭头函数最大的特点就是有箭头“=>” 符号,它有很多变式写法:

  • 没有参数时,用括号()代替;
  • 一个参数时,括号可以省略;
  • 多个参数时,(arg1,agr2...)
    如下:
//没有参数时,用括号()代替;
var fun=()=>'123';
console.log(fun());  //123   
//一个参数时,括号可以省略;
var fun=arg=>arg;
console.log(fun('123'));  //123   
//多个参数时;
var fun=(arg1,arg2)=>arg1+arg2;
console.log(fun(1,5));  //6  

也可以手动返回数据;

var fun=arg=>{ 
return arg;
};
console.log(fun('123'));  //123  

注意点

注意点1:利用箭头函数隐式返回的时候需要注意,数据是对象时的情况,比如以下错误的情况:

var fun=arg=>{ 
 name:'静静',
 age:18
};

这里返回数据实际上是个对象,但是它的大括号和函数本身的大括号有冲突,系统会默认为是函数的大括号,导致报错。所以应改为如下:

var fun=arg=>{{
 name:'静静',
 age:18
}};
console.log(fun()); //{name:'静静',age:18} 

注意点2箭头函数里没有this绑定,如下代码,箭头函数里面的this指向对象本身:

var obj={
 name:'静静',
 age:18,
 fun:function(){
  console.log(this.name);//静静
 }
}

obj里fun的this指向obj,所以能找到name, 现将obj里面的fun函数改成箭头函数,会发生什么?

var obj={
 name:'静静',
 age:18,
 fun:()=>{
  console.log(this.name);//undefined
 }
}

因为箭头函数fun里面没有this绑定,因此箭头函数会指向最近的的上层this,所以这里的this指向的是window,因此找不到name的值。
注意点3没有隐藏参数arguments的绑定;
使用箭头函数时还须注意没有参数arguments的绑定,看如下代码:

var fun=(arg1,arg2)=>{
console.log(arguments);//arguments is not defined
return arg1+arg2
};
console.log(fun(1,5));  //6  

箭头函数的重要特征

重要特征:箭头函数可让函数内的this与函数外的this保持一致
因为箭头函数里没有this绑定,箭头函数会指向最近的的上层this,所以说:箭头函数可让函数内的this与函数外的this保持一致。

什么情况下使用箭头函数

如果函数中不包含this,或刚好希望函数内的this与外部this保持一致时,就可以改为箭头函数;
如果反而不希望函数内的this与函数外的this保持一致时,都不能改成箭头函数;

误区

箭头函数没有、不是作用域,这是错误错误错误的,重要的事说三遍。
箭头函数只让this,指向外部作用域的this,而箭头函数内的局部变量,依然只能在箭头函数内使用,出了箭头函数不能用,所以,箭头函数依然是作用域,只不过影响this而已,不影响局部变量;

箭头函数底层原理

有没有发现一个问题:把函数改成bind效果和箭头函数的效果一样?! 看如下代码:

var obj={
    name:'静静',
    age:18,
    friends:['小明','小红','小月'],
    fun:function(){
        console.log(`fun里面的this=====>${JSON.stringify(this)}`);
        //this.fiends:['小明','小红','小月']
       this.friends.forEach(
           function(friend){
               //this.name为undefined
               console.log(`forEach里面的函数this=====>${this}`);
               console.log(`${this.name}的朋友是${friend}`);
            }
       )
    }
}
obj.fun();

看输出:
image.png fun里面this.friedns值为:['小明','小红','小月'],this指的是obj,但是ForEach里面function的this指向window,因此没有找到name值,值为undefined。我们如果给function加个bind会怎么样,看如下代码:

var obj={
    name:'静静',
    age:18,
    friends:['小明','小红','小月'],
    fun:function(){
        console.log(`fun里面的this=====>${JSON.stringify(this)}`);
        //this.fiends:['小明','小红','小月']
       this.friends.forEach(
           function(friend){
               //this.name为undefined
               console.log(`forEach里面的函数this=====>${JSON.stringify(this)}`);
               console.log(`${this.name}的朋友是${friend}`);
            }.bind(this)
       )
    }
}
obj.fun();

看下输出:
image.png
发现加上bind后,this指向变了,this指向了obj,我们再看一下,改成箭头函数,代码如下:

var obj={
    name:'静静',
    age:18,
    friends:['小明','小红','小月'],
    fun:function(){
        console.log(`fun里面的this=====>${JSON.stringify(this)}`);
        //this.fiends:['小明','小红','小月']
       this.friends.forEach(
           (friend)=>{
               //this.name为undefined
               console.log(`改成箭头函数后:forEach里面的函数this=====>${JSON.stringify(this)}`);
               console.log(`${this.name}的朋友是${friend}`);
            }
       )
    }
}
obj.fun();

看下输出:
image.png forEach里面的函数this指向也变成了obj;
forEach里面的函数,无论是加bind,还是写成箭头函数,他们的this指向是一样的,效果也是一样的,所以说:箭头函数底层相当于.bind(); 永远绑定外部this;
所以call无法替换箭头函数中的this;

总结

  • 箭头函数是es6里面的新语法,返回对象时,不要省略函数的大括号,因为,系统默认对象的大括号就是函数的大括号,会导致报错;
  • 箭头函数没有this的绑定,也没有隐藏参数arguments的绑定;
  • 箭头函数可让函数内的this与函数外的this保持一致;
  • 箭头函数是有自己作用域的,本身是一个作用域;
  • 箭头函数的底层原理:底层相当于.bind(),并且永远绑定外部的this,因此,call无法替换箭头函数中的this;