ES6箭头函数(节选自《ECMAScript 6 入门》)

主旨用法

ES6 允许行使“箭头”(=>)定义函数。

var f = v => v;

 

地点的箭头函数等同于:

var f = function(v) {
  return v;
};

 

假若箭头函数不必要参数或需求七个参数,就利用二个圆括号表示参数部分。

var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

 

一经箭头函数的代码块部分多于一条语句,就要接纳大括号将它们括起来,并且应用return语句重临。

var sum = (num1, num2) => { return num1 + num2; }

 

鉴于大括号被演讲为代码块,所以一旦箭头函数直接重返3个目的,必须在指标外面加上括号。

var getTempItem = id => ({ id: id, name: "Temp" });

 

箭头函数能够与变量解构结合使用。

const full = ({ first, last }) => first + ' ' + last;

// 等同于
function full(person) {
  return person.first + ' ' + person.last;
}

 

箭头函数使得表明更为简洁。

const isEven = n => n % 2 == 0;
const square = n => n * n;

 

地方代码只用了两行,就定义了多个简易的工具函数。假使不用箭头函数,大概就要占用多行,而且还不如将来如此写醒目。

箭头函数的二个用处是简化回调函数。

// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});

// 箭头函数写法
[1,2,3].map(x => x * x);

 

另三个例证是

// 正常函数写法
var result = values.sort(function (a, b) {
  return a - b;
});

// 箭头函数写法
var result = values.sort((a, b) => a - b);

 

上边是 rest 参数与箭头函数结合的例子。

const numbers = (...nums) => nums;

numbers(1, 2, 3, 4, 5)
// [1,2,3,4,5]

const headAndTail = (head, ...tail) => [head, tail];

headAndTail(1, 2, 3, 4, 5)
// [1,[2,3,4,5]]

 

动用注意点

箭头函数有多少个应用注意点。

(1)函数体内的this对象,正是概念时所在的对象,而不是选择时所在的指标。

(2)不能当做构造函数,也正是说,不可以应用new一声令下,不然会抛出3个谬误。

(3)不得以行使arguments目的,该指标在函数体内不设有。假设要用,能够用
rest 参数代替。

(4)不可能利用yield命令,由此箭头函数不可能用作 Generator 函数。

上边四点中,第2点更为值得注意。this目的的对准是可变的,然则在箭头函数中,它是一定的。

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

 

地点代码中,setTimeout的参数是一个箭头函数,那一个箭头函数的定义生效是在foo函数生成时,而它的着实履行要等到100皮秒后。若是是平时函数,执行时this应该针对全局对象window,那时应该出口21。可是,箭头函数导致this老是指向函数定义生效时所在的目的(本例是{id: 42}),所以输出的是42

箭头函数能够让setTimeout里面的this,绑定定义时所在的功效域,而不是指向运维时所在的作用域。上边是另二个事例。

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0

 

地方代码中,Timer函数内部安装了七个定时器,分别采纳了箭头函数和常见函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this本着运转时所在的效率域(即全局对象)。所以,3100皮秒之后,timer.s1被更新了1遍,而timer.s2贰遍都没更新。

箭头函数能够让this针对固定化,那种特征很有利封装回调函数。下边是五个例子,DOM
事件的回调函数封装在1个对象里面。

var handler = {
  id: '123456',

  init: function() {
    document.addEventListener('click',
      event => this.doSomething(event.type), false);
  },

  doSomething: function(type) {
    console.log('Handling ' + type  + ' for ' + this.id);
  }
};

 

上边代码的init方法中,使用了箭头函数,那致使这几个箭头函数里面包车型地铁this,总是指向handler对象。不然,回调函数运转时,this.doSomething这一行会报错,因为那时候this指向document对象。

this本着的固定化,并不是因为箭头函数内部有绑定this的建制,实际原因是箭头函数根本没有团结的this,导致个中的this就是外围代码块的this。便是因为它并未this,所以也就不能够用作构造函数。

故此,箭头函数转成 ES5 的代码如下。

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}

 

上边代码中,转换后的ES5本子清楚地表达了,箭头函数里面平昔没有和谐的this,而是引用外层的this

试问上边包车型地铁代码之中有多少个this

function foo() {
  return () => {
    return () => {
      return () => {
        console.log('id:', this.id);
      };
    };
  };
}

var f = foo.call({id: 1});

var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1

 

上边代码之中,唯有二个this,便是函数foothis,所以t1t2t3都输出同样的结果。因为拥有的内层函数都以箭头函数,都并未自个儿的this,它们的this实则都以最外层foo函数的this

除了this,以下八个变量在箭头函数之中也是不存在的,指向外层函数的相应变量:argumentssupernew.target

function foo() {
  setTimeout(() => {
    console.log('args:', arguments);
  }, 100);
}

foo(2, 4, 6, 8)
// args: [2, 4, 6, 8]

 

位置代码中,箭头函数内部的变量arguments,其实是函数fooarguments变量。

此外,由于箭头函数没有自个儿的this,所以本来也就不可能用call()apply()bind()那些点子去改变this的指向。

(function() {
  return [
    (() => this.x).bind({ x: 'inner' })()
  ];
}).call({ x: 'outer' });
// ['outer']

 

上面代码中,箭头函数没有协调的this,所以bind措施行不通,内部的this针对外部的this

短时间以来,JavaScript
语言的this对象一向是1个令人讨厌的题材,在目的方法中应用this,必须相当小心。箭头函数”绑定”this,非常大程度上缓解了这几个麻烦。

嵌套的箭头函数

箭头函数内部,仍是能够再利用箭头函数。上边是叁个 ES5 语法的多级嵌套函数。

function insert(value) {
  return {into: function (array) {
    return {after: function (afterValue) {
      array.splice(array.indexOf(afterValue) + 1, 0, value);
      return array;
    }};
  }};
}

insert(2).into([1, 3]).after(1); //[1, 2, 3]

 

上边这几个函数,可以动用箭头函数改写。

let insert = (value) => ({into: (array) => ({after: (afterValue) => {
  array.splice(array.indexOf(afterValue) + 1, 0, value);
  return array;
}})});

insert(2).into([1, 3]).after(1); //[1, 2, 3]

 

上面是多少个布局管道机制(pipeline)的例证,即前1个函数的出口是后1个函数的输入。

const pipeline = (...funcs) =>
  val => funcs.reduce((a, b) => b(a), val);

const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);

addThenMult(5)
// 12

 

一旦认为上面的写法可读性比较差,也能够采用上边包车型客车写法。

const plus1 = a => a + 1;
const mult2 = a => a * 2;

mult2(plus1(5))
// 12

 

箭头函数还有多个成效,正是能够很便宜地改写λ演算。

// λ演算的写法
fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v)))

// ES6的写法
var fix = f => (x => f(v => x(x)(v)))
               (x => f(v => x(x)(v)));

 

地点三种写法,大约是逐一对应的。由于λ演算对于电脑科学万分关键,那使得大家能够用ES6看作代表工具,探索总计机科学。

 

附:《ECMAScript 6
入门
http://es6.ruanyifeng.com/