箭头函数小抄

324 阅读3分钟

翻译:dejun 原文 Arrow Functions Shortening Recipes in JavaScript,有删减编辑。


用箭头函数能定义更短小的函数。比如下面的可以省略:

  • 参数括号 (形参1, 形参2)
  • return 关键字
  • 甚至花括号{ }.

让箭头函数变得更精简易读,需要注意的小技巧:

1. 基本语法

箭头函数的完整版本包括:

一对包着参数的括号(形参1, 形参2),跟着一个箭头 =>,以{函数体}结束

例如:

const sayMessage = (what, who) => {
  return `${what}, ${who}!`;
};

sayMessage('Hello', 'World'); // => 'Hello, World!'

这里有个注意点: (参数1, 参数2) 和 => 之间不能有空行.

来看看让函数精简易懂的几种方式,尤其在处理回调的时:

2. 省略参数括号

greet函数有一个参数:

const greet = (who) => {
  return `${who}, Welcome!`
};
greet('Aliens'); // => "Aliens, Welcome!"

greet箭头函数只有一个who. 参数有括号.

这种情况,当只有一个参数时,可以省略括号改成下面所示:

const greetNoParentheses = who => {
  return `${who}, Welcome!`
};
greetNoParentheses('Aliens'); // => "Aliens, Welcome!"

即使只省两个字符,也是胜利✌️。

有几种情况不能省略括号:

2.1 有默认参数的情况

有默认参数,必须保留括号

const greetDefParam = (who = 'Martians') => {
  return `${who}, Welcome!`
};
greetDefParam(); // => "Martians, Welcome!"

2.2 有参数解构的情况

有参数解构时,保留括号:

const greetDestruct = ({ who }) => {
  return `${who}, Welcome!`;
};
const race = {
  planet: 'Jupiter',
  who: 'Jupiterians'
};
greetDestruct(race); // => "Jupiterians, Welcome!"

函数的唯一参数解构了 { who } 来访问对象属性who. 这种情况下, 要用括号.

2.3 没有参数的情况

当函数没有参数时, 括号也要保留:

const greetEveryone = () => {
  return 'Everyone, Welcome!';
}

greetEveryone(); // => "Everyone, Welcome!"

greetEveryone没有任何参数. 参数括号()保留.

3. 省略{}和return

如果箭头函数体只包含一个表达式, 你可以省略花括号 { } 和return关键字. 不用担心省略return,箭头函数隐式返回了表达式计算结果。 这是我最喜欢的箭头函数语法.

greetConcise函数没有花括号{ }和return:

const greetConcise = who => `${who}, Welcome!`;

greetConcise('Friends'); // => "Friends, Welcome!"

greetConcise是箭头函数语法的精简版. 直接返回表达式${who}, Welcome!,甚至省略了返回值的括号。

3.1 返回对象字面量的时候需注意

当使用最简箭头函数语法并返回一个对象字面量时,你可能会碰到与自己预期不一致的情况。

比如:

const greetObject = who => { message: `${who}, Welcome!` };

greetObject('Klingons'); // => undefined

期望greetObject返回一个object,实际上返回了undefined.

问题是javascript认为{ }是函数体分界符, 而不是对象字面量. message被翻译成标识符,而不是一个对象的属性。

为了让这个函数返回一个对象, 需要把这个对象用()包起来:

const greetObject = who => ({ message: `${who}, Welcome!` });
greetObject('Klingons'); // => { message: `Klingons, Welcome!` }

({ message: `${who}, Welcome!` })是一个表达式. 现在javascript终于会把这个看成一个对象了.

4. 箭头方法

类的域提案 (2019.8 在stage3) 给类引入了箭头方法的语法. 方法里的this始终绑定了类的实例.

在此定义一个Greet的类,里面包含箭头方法:

class Greet {
  constructor(what) {
    this.what = what;
  }
  getMessage = (who) => {
    return `${who}, ${this.what}!`;
  }
}
const welcome = new Greet('Welcome');
welcome.getMessage('Romulans'); // => 'Romulans, Welcome!'

getMessage是Greet class定义的箭头方法。 getMessage方法里的this始终绑定了类的实例。

这里也可以使用最简的箭头方法。 比如,简化的getMessage方法:

class Greet {
  constructor(what) {
    this.what = what;
  }
  getMessage = who => `${who}, ${this.what}!`
}
const welcome = new Greet('Welcome');
welcome.getMessage('Romulans'); // => 'Romulans, Welcome!'

getMessage = who => `${who}, ${this.what}!` 是精简的箭头函数定义。参数括号,函数体花括号{ }和return关键字全部省掉了.

5. 考虑到代码可读性,并不是越短越好。

箭头函数的简洁是我们立刻展示函数的功能。

const numbers = [1, 4, 5];
numbers.map(x => x * 2); // => [2, 8, 10]
x => x * 2 简明地展示x乘以2.

最简语法看起来很棒,不过需要理智地使用,否则会引起代码可读方面的问题,尤其是在多重嵌套箭头的函数的情况中。

比起减少短代码,我更加看重可读,因此有些情况下,我会保留花括号和return关键字。

定义一个简洁的工厂函数:

const multiplyFactory = m => x => x * m;

const double = multiplyFactory(2);
double(5); // => 10

尽管multiplyFactory很短, 但是不容易让人一眼看出来想做什么。

遇到这种情况,我们避免用最简语法,让函数定义长一点:

const multiplyFactory = m => { 
  return x => x * m;
};

const double = multiplyFactory(2);
double(5); // => 10

这里使用稍长一点的定义, multiplyFactory能让人更快理解,它返回一个箭头函数。 每人都有自己的品位和喜好,不过我建议你把代码可读性的优先级置于简短的前面。

6. 总结

箭头函数有精简函数定义的能力。

通过上面的小技巧,你可以通过移除参数括号,函数体花括号,和return关键字来精简函数

最新提案,你可以在类里用箭头方法。

然而,简短可能会降低可读性,如果你有很多嵌套的函数,那么最好避免最精简的形式。