一、创建函数还有另外一种非常简单的语法,箭头函数表达式(也称胖箭头函数)相比函数表达式具有较短的语法并以词法的方式绑定this。
二、箭头函数总是匿名的。
三、箭头函数可以像函数表达式一样使用。
【示例1】动态创建一个函数:

  1. let age = prompt("What is your age?", 18);
  2. let welcome = (age < 18) ?
  3. () => alert('Hello') :
  4. () => alert("Greetings!");
  5. welcome();

四、箭头函数:

  • 没有this
  • 没有arguments
  • 不能使用new进行调用
  • 它们也没有super,但目前我们还没有学到它。我们将在类继承一章中学习它。

五、箭头函数是针对那些没有自己的“上下文”,但在当前上下文中起作用的短代码的

创建箭头函数

一行的箭头函数

一、语法:
1、不带花括号:

let func = (...args) => expression

(1)右侧是一个表达式:函数计算表达式并返回其结果。
2、带花括号:

let func = (...args) => { body }

花括号允许我们在函数中编写多个语句,但是我们需要显式地return来返回一些内容。
二、下面的代码创建了一个函数func,它接受参数arg1..argN,然后使用参数对右侧的expression求值并返回其结果。

let func = (arg1, arg2, ...argN) => expression

1、换句话说,它是下面这段代码的更短的版本:

let func = function(arg1, arg2, ...argN) {
  return expression;
};

【示例1】具体的例子:

let sum = (a, b) => a + b;

/* 这个箭头函数是下面这个函数的更短的版本:

let sum = function(a, b) {
  return a + b;
};
*/

alert( sum(1, 2) ); // 3

1、可以看到(a, b) => a + b表示一个函数接受两个名为a和b的参数。在执行时,它将对表达式a + b求值,并返回计算结果。
(1)如果我们只有一个参数,还可以省略掉参数外的圆括号,使代码更短。

let double = n => n * 2;
// 差不多等同于:let double = function(n) { return n * 2 }

alert( double(3) ); // 6

(2)如果没有参数,括号将是空的(但括号应该保留):

let sayHi = () => alert("Hello!");
sayHi();

多行的箭头函数

一、下面的例子从=>的左侧获取参数,然后使用参数计算右侧表达式的值

let sum = (a, b) => a + b;
alert( sum(1, 2) ); // 3

1、但有时我们需要更复杂一点的东西,比如多行的表达式或语句。
(1)我们应该用花括号括起来。然后使用一个普通的return将需要返回的值进行返回。
【示例1】

let sum = (a, b) => {  // 花括号表示开始一个多行函数
  let result = a + b;
  return result; // 如果我们使用了花括号,那么我们需要一个显式的 “return”
};

alert( sum(1, 2) ); // 3

影响引入箭头函数的因素

一、有两个因素会影响引入箭头函数:更简洁的函数和this

更简洁的函数

一、【实例1】

var a = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryllium"
];

var a2 = a.map(function(s){ return s.length });

console.log(a2); // logs [ 8, 6, 7, 9 ]

var a3 = a.map( s => s.length );

console.log(a3); // logs [ 8, 6, 7, 9 ]

this的词法

一、箭头函数出现之前,每一个新函数都重新定义了自己的this值(在构造函数中是一个新的对象;在严格模式下是未定义的;在作为“对象方法”调用的函数中指向这个对象;等等)
【实例1】

function Person() {
  // 构造函数Person()将`this`定义为自身
  this.age = 0;

  setInterval(function growUp() {
    // 在非严格模式下,growUp()函数将`this`定义为“全局对象”,
    // 这与Person()定义的`this`不同,
    // 所以下面的语句不会起到预期的效果。
    this.age++;
  }, 1000);
}

var p = new Person();

【实例2】ECMAScript 3/5里,通过把this的值赋值给一个变量可以修复这个问题

function Person() {
  var self = this; // 有的人习惯用`that`而不是`self`,
                   // 无论你选择哪一种方式,请保持前后代码的一致性
  self.age = 0;

  setInterval(function growUp() {
    // 以下语句可以实现预期的功能
    self.age++;
  }, 1000);
}

【实例3】创建一个约束函数可以似的this值被正确传递给groupUp()函数。
约束函数:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
【实例4】箭头函数捕捉闭包上下文的this值

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // 这里的`this`正确地指向person对象
  }, 1000);
}

var p = new Person();

箭头函数没有 “this”

见this#值-箭头函数:https://www.yuque.com/tqpuuk/yrrefz/gcb2wp

不能对箭头函数进行new操作

一、箭头函数不具有this自然也就意味着另一个限制:箭头函数不能用作构造器(constructor)。不能用new调用它们。

箭头函数 VS bind

一、箭头函数=>和使用.bind(this)调用的常规函数之间有细微的差别:

  • .bind(this)创建了一个该函数的“绑定版本”。
  • 箭头函数=>没有创建任何绑定。箭头函数只是没有this。this的查找与常规变量的搜索方式完全相同:在外部词法环境中查找。

    箭头函数没有 “arguments”

    一、箭头函数也没有arguments变量。
    二、当我们需要使用当前的this和arguments转发一个调用时,这对装饰器(decorators)来说非常有用。
    【示例1】defer(f, ms)获得了一个函数,并返回一个包装器,该包装器将调用延迟ms毫秒: ```javascript function defer(f, ms) { return function() { setTimeout(() => f.apply(this, arguments), ms) }; }

function sayHi(who) { alert(‘Hello, ‘ + who); }

let sayHiDeferred = defer(sayHi, 2000); sayHiDeferred(“John”); // 2 秒后显示:Hello, John

1、不用箭头函数的话,可以这么写:
```javascript
function defer(f, ms) {
  return function(...args) {
    let ctx = this;
    setTimeout(function() {
      return f.apply(ctx, args);
    }, ms);
  };
}

(1)在这里,我们必须创建额外的变量args和ctx,以便setTimeout内部的函数可以获取它们。