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; }

 

鉴于大括如泣如诉于解说也代码块,所以一旦箭头函数直接返回一个靶,必须以靶之外加上括号。

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)不得以用arguments靶,该目标在函数体内不在。如果一旦为此,可以为此
rest 参数代替。

(4)不得以使用yield一声令下,因此箭头函数不克用作 Generator 函数。

地方四沾着,第一点更为值得注意。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深受更新了3赖,而timer.s2一如既往潮都无更新。

箭头函数可以吃this针对固定化,这种特点很便宜封装回调函数。下面是一个例,DOM
事件的回调函数查封装在一个目标中。

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()这些ECMAScript主意去改变this的指向。

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

 

地方代码中,箭头函数没有协调的this,所以bind主意行不通,内部的this本着外部的this

长期以来,JavaScript
语言的this目标一直是一个令人讨厌的问题,在对象方法吃以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)的事例,即眼前一个函数的输出是继一个函数的输入。

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/