箭头函数基本语法及其与普通函数关系 | 青训营

60 阅读3分钟

箭头函数

MDN:

箭头函数表达式的语法比函数表达式更简洁,并且没有自己的thisargumentssupernew.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。

摘自:箭头函数 - JavaScript | MDN (mozilla.org)

语法

1. 基础语法

  • 当只有一个参数时,圆括号是可选的
  • 没有参数的函数应该写成一对圆括号
  (param1, param2, …, paramN) => { statements }
  (param1, param2, …, paramN) => expression
  //相当于:(param1, param2, …, paramN) =>{ return expression; }
  ​
  ​
  (singleParam) => { statements }
  singleParam => { statements }
  ​
  () => { statements }

2.高级语法

  • 加括号的函数体返回对象字面量表达式
  • 支持剩余参数和默认参数
  • 支持参数列表解构
params => ({foo: bar})
  ​
  (param1, param2, ...rest) => { statements }
  (param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
  statements }
  ​
  let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
  f();  // 6

3. 更短的语法

  • 当使用mapforEachfliterfindsome……时,可以使用如下方式:
  elements.map(function (element) {
    return element.length;
  }); // 返回数组:[8, 6, 7, 9]
  ​
  elements.map((element) => {
    return element.length;
  • 当箭头函数只有一个参数时,可以省略参数的圆括号
  elements.map(element => {
    return element.length;
  }); // [8, 6, 7, 9]
  • 当箭头函数的函数体只有一个 return 语句时,可以省略 return 关键字和方法体的花括号
  elements.map((element) => element.length); // [8, 6, 7, 9]
  • 可以使用参数解构,替换成任意合法的变量名
  
  elements.map(({ length: lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]

没有单独的this

在箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的 this 值:

  • 如果该函数是一个构造函数,this 指针指向一个新的对象
  • 在严格模式下的函数调用下,this 指向undefined
  • 如果该函数是一个对象的方法,则它的 this 指针指向这个对象
  • 等等

在 ECMAScript 3/5 中,通过将this值分配给封闭的变量,可以解决this问题。

或者,可以创建绑定函数,以便将预先分配的this值传递到绑定的目标函数(上述示例中的growUp()函数)。

  • 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承 this。因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同:
  function Person() {
    this.age = 0;
  ​
    setInterval(() => {
      this.age++; // |this| 正确地指向 p 实例
    }, 1000);
  }
  ​
  var p = new Person();

与严格模式的关系

鉴于 this 是词法层面上的,严格模式中与 this 相关的规则都将被忽略。

  var f = () => { 'use strict'; return this; };
  f() === window; // 或者 global

通过 call 或 apply 调用

由于 箭头函数没有自己的 this 指针,通过 call() apply() 方法调用一个函数时,只能传递参数,他们的第一个参数会被忽略。(这种现象对于 bind 方法同样成立)

JSCopy to Clipboard

  var adder = {
    base: 1,
  ​
    add: function (a) {
      var f = (v) => v + this.base;
      return f(a);
    },
  ​
    addThruCall: function (a) {
      var f = (v) => v + this.base;
      var b = {
        base: 2,
      };
  ​
      return f.call(b, a);
    },
  };
  ​
  console.log(adder.add(1)); // 输出 2
  console.log(adder.addThruCall(1)); // 仍然输出 2

不绑定arguments

  • 箭头函数不绑定Arguments 对象。因此,在本示例中,arguments只是引用了封闭作用域内的 arguments
  • 在大多数情况下,使用剩余参数是相较使用arguments对象的更好选择。
  function foo(arg) {
    var f = (...args) => args[0];
    return f(arg);
  }
  foo(1); // 1
  ​
  function foo(arg1, arg2) {
    var f = (...args) => args[1];
    return f(arg1, arg2);
  }
  foo(1, 2); //2

函数体

  • 箭头函数可以有一个“简写体”或常见的“块体”。
  • 在一个简写体中,只需要一个表达式,并附加一个隐式的返回值。在块体中,必须使用明确的return语句。
  var func = (x) => x * x;
  // 简写函数 省略 returnvar func = (x, y) => {
    return x + y;
  };
  //常规编写 明确的返回值

返回对象字面量

  • 记住用params => {object:literal}这种简单的语法返回对象字面量是行不通的。
  var func = () => { foo: 1 };
  // Calling func() returns undefined!var func = () => { foo: function() {} };
  // SyntaxError: function statement requires a name

这是因为花括号({} )里面的代码被解析为一系列语句(即 foo 被认为是一个标签,而非对象字面量的组成部分)。

记得用圆括号把对象字面量包起来:

  var func = () => ({ foo: 1 });