【ES6基础】箭头函数(Arrow functions)

ES6中,除了let和const新特性,箭头函数是使用频率最高的新特性了。若是你曾经了解如日中天的JavaScript衍生语言CoffeeScript, 就会清楚此特性并不是ES6首创。箭头函数顾名思义是使用箭头(=>)定义的函数,属于匿名函数一类。javascript

今天的文章内容将会从如下几个方面,介绍箭头函数:前端

  • 使用语法
  • this穿透
  • 箭头函数和传统函数的区别

本篇文章阅读时间预计8分钟java

使用语法

箭头函数有四种使用语法数组

一、单一参数的单行箭头函数微信

以下段代码所示,很简单:函数

const fn= foo =>`${foo} world`;复制代码

这是箭头函数最简洁的形式,经常使用于用做简单的处理函数,如过滤。以下段代码所示:post

let array=['a','bc','def','ghij'];
array=array.filter(item=>item.length>=2);复制代码

二、多参数的单行箭头函数 语法也很简单,以下段代码所示:ui

const fn=(foo,bar) => foo+bar复制代码

在实际开发中,函数的参数不会只有一个,在箭头函数中,多参数的语法跟普通函数同样,用括号包裹参数项。咱们常常处理函数,如排序,示例代码以下:this

let array=['a','bc','def','ghij'];
array=array.sort((a,b) => a.length < b.length);复制代码

三、多行箭头函数 单一参数,以下段代码所示:spa

foo => {
    return `${foo} world`;
}复制代码

多参数,以下段代码所示:

(foo,bar) => {
    return foo+bar;
}复制代码

四、无参数箭头函数

若是一个箭头函数无参数传入,则须要用一对空的括号来表示空的参数列表。

const greet = () => 'Hello World'复制代码

以上都是被支持的箭头函数的表达方式,其最大的好处就是简单明了,省略了function关键字,而使用 => 代替。相对于传统的function函数,箭头函数在简单的函数使用中更为简洁直观。

书写箭头的函数过程当中,咱们应该注意如下几点:

一、使用单行箭头函数时,应避免换行

错误的用法,以下段代码所示:

const fn=x => x*2 //SyntaxError复制代码

正确的写法,以下:

const fn= x => x*2 //ok复制代码

二、参数列别的右括弧、箭头应在一行

错误的用法,以下段代码所示:

const fn = (x,y) //SyntaxError
=> {
   return x*y;
}复制代码

下段代码书写是正确的:

const fn= (x,y) => { //ok
    return x*y
}

const fn= (x,
           y) => { //ok
    return x*y        
}复制代码

三、单行箭头函数返回只能包含一条语句

错误的书写,以下段代码所示:

const fn1= x => x=x*2; return x+2; //SyntaxError复制代码

正确的书写,以下段代码所示:

const fn2= x => {
    x=x*2;
    return x+2;
} //ok复制代码

四、若是单行箭头返回一个对象,请用圆括号包裹

错误的书写,以下段代码所示,解析引擎会将其解析成一个多行箭头函数:

const ids=[1,2,3];
const users=ids.map(id=>{id:id});
//wrong:[ undefined, undefined, undefined ]复制代码

正确的书写,以下段代码所示:

const ids=[1,2,3];
const users=ids.map(id=>({id:id}));
//Correct:[ { id: 1 }, { id: 2 }, { id: 3 } ]复制代码

箭头函数十分简洁,特别适合单行回调函数的定义,好比咱们有如下需求:

咱们有一个这样的名字数组names,['Will','Jack','Peter','Steve','John','Hugo','Mike'],输出序号为偶数的名字[ 'Will', 'Peter', 'John', 'Mike' ],咱们如何使用箭头函数在一行语句完成呢,以下段代码所示:

const names=['Will','Jack','Peter','Steve','John','Hugo','Mike'];
const newSet=names
.map((name,index)=>({
    id:index,
    name:name
}))
.filter(man => man.id %2 ==0)
.map(man => [man.name])
.reduce((a,b) => a.concat(b))复制代码

this穿透

事实上,箭头函数不只书写简洁,还有一个神奇的功能,就是将函数内部的this延伸上一层做用域中,及上一层的上下文会穿透到内层的箭头函数中,让咱们先看一段实际的例子,以下段所示:

var Widget={
  // A
    init:function () {
    // B
        document.addEventListener("click", function (event){
    //C
            this.doSomething(event.type);
        }, false);
    },
    doSomething:function (type) {
        console.log("Handling"+ type+"event");
    }
};
Widget.init();复制代码

这段代码会如何输出呢,想必你们都猜到了吧,输出undefined,为何呢?咱们在B位置内声明了函数(C区域),this关键词的指向B区域的函数,因为B区域内没有doSomething函数声明,所以输出undefined,ES6以前咱们如何修正此问题呢?

咱们可使用bind方法改变this指向A区域Widget对象,示例代码以下:

var Widget={
  // A
    init:function () {
        // B
        document.addEventListener("click", (function (event) {
            //C
            this.doSomething(event.type);
        }).bind(this), false);
    },
    doSomething:function (type) {
        console.log("Handling"+ type+"event");
    }
};
Widget.init();复制代码

下面这种方法是咱们最经常使用的方法,咱们在B区域声明了that变量,并将其this赋值,确保c区域this的指向至Widget对象:

var Widget={
 // A
    init:function () {
        // B
        var that=this;
        document.addEventListener("click", function (event) {
                //C
            that.doSomething(event.type);
            console.log(that);
        }, false);
    },
    doSomething:function (type) {
        console.log("Handling"+ type+"event");
    }
};
Widget.init();复制代码

有了箭头函数,咱们可使用箭头函数的this穿透功能,将this的做用域延伸至上一层B区域函数,以下段代码所示:

var Widget={
//A
    init:function () {
    //B
        document.addEventListener("click", (event) => {
        //C
            this.doSomething(event.type);
        }, false);
    },
    doSomething:function (type) {
        console.log("Handling"+ type+"event");
    }
};
Widget.init();复制代码

箭头函数是否是更简单,代码更清晰呢。

还有一个状况须要注意,箭头函数对上下文的绑定是强制的,没法经过call或aplly进行改变,以下段代码所示:

function widget() {
    this.id=123;
    this.log=()=>{
      console.log(this)
        console.log('widget log',this.id);
    }
}

var pseudoWidget={
    id:456
};

new widget().log.call(pseudoWidget);//123复制代码

上述代码会如何输出呢,因为箭头函数对上下文的绑定是强制的,所以this指向不会指向pseudoWidget对象,所以输出123。

箭头函数和传统函数的区别

一、箭头函数做为匿名函数,是不能做为构造函数的,不能使用new

以下段代码所示,咱们使用new方法,会提示以下信息:

const B =()=>({wechat:"前端达人"});
let b = new B(); //TypeError: B is not a constructor复制代码

二、箭头函数不绑定arguments,可使用剩余参数(rest)解决

笔者在《【ES6基础】展开语法(Spread syntax)》文章里介绍过剩余参数,这里就不过多介绍,不清楚的能够点击文章连接进行查看。

function A(a){
    console.log(arguments); //[object Arguments] {0: 1}
}

var B = (b)=>{
    console.log(arguments); //ReferenceError: arguments is not defined
}

var C = (...c)=>{ //...c即为rest参数
    console.log(c); //[3]
}
A(1);
B(2);
C(3);复制代码

三、箭头函数this指向具有穿透特性,会捕获其所在上下文的this值

四、箭头函数没有原型属性

var a = ()=>{
    return '前端达人';
}

function b(){
    return '前端达人';
}
console.log(a.prototype);//undefined
console.log(b.prototype);//object{...}复制代码

五、箭头函数不能当作Generator函数,不能使用yield关键字

六、箭头函数对上下文的绑定是强制的,没法经过call或aplly进行改变

小节

今天的内容就介绍到这里,咱们能够看出使用箭头函能减小代码量,更加简介易读。在使用箭头函数时,咱们必定要理解箭头函数和传统函数的区别,若是函数功能简单,只是简单的逻辑处理,尽可能使用箭头函数。

ES6相关文章

【ES6基础】let和做用域

【ES6基础】const介绍

【ES6基础】默认参数值

【ES6基础】展开语法(Spread syntax)

【ES6基础】解构赋值(destructuring assignment)

更多精彩内容,请微信关注”前端达人”公众号!

相关文章
相关标签/搜索