箭头功能值得流行. 它的语法简洁明了, 使用词法绑定绑定 this, 它非常适合作为回调. 在本文中, 通过了解决学习 5 个最佳实践, 以便我们可以从中学习更多箭头函数的知识, 并从它身上获得更多的好处.
1. 箭头函数名推断
JS 中的箭头函数是 匿名(anonymous) 的: 函数的 name 属性是 '' .
( number => number + 1 ).name; // => ''
在调试会话或调用堆栈分析期间, 匿名函数被标记为 anonymous . 不幸的是, anonymous 程序不提供有关正在执行的代码的任何线索.
这里是执行匿名函数的代码的调试会话:
右边的调用堆栈由两个标记为 anonymous 的函数组成, 我们无法从这样的调用堆栈信息中获得任何有用的信息.
幸运的是, 函数名推断 (ES2015 的功能) 可以在某些条件下检测到函数名称. 名称推断的思想是 JS 可以从其语法位置确定箭头函数名称: 从保存函数对象的变量名称中获取.
我们来看看函数名称推断的工作原理:
- const increaseNumber = number => number + 1;
- increaseNumber.name; // => 'increaseNumber'
因为变量 increaseNumber 保存了箭头函数, 所以 JS 决定使用 increaseNumber 作为该函数的名称. 因此, 箭头函数的名称为'increaseNumber' .
第 1 个实践:
一个好的做法是使用函数名称推断来命名箭头函数.
现在我们用使用名称推断的代码检查一个调试会话:
因为箭头函数有名称, 所以调用堆栈提供了有关正在执行的代码的更多信息.
- handleButtonClick
- gainCounter
2. 尽可能使用内联方式
内联函数是仅具有一个表达式的函数. 我喜欢箭头功能, 可以编写短内联函数.
例如, 不要使用箭头函数的长形式:
- const array = [1, 2, 3];
- array.map((number) => {
- return number * 2;
- });
当箭头函数只有一个表达式时, 可以轻松地删除大括号 {} 和 return 语句:
- const array = [1, 2, 3];
- array.map(number => number * 2);
第 2 个实践:
当函数只有一个表达式时, 一个好的做法是使用内联箭头函数格式
3. 胖箭头和比较运算符
比较操作符 > , < , <= 和 >= 看起来类似于 f 胖箭头 => (它定义了箭头函数). 当在内联箭头函数中使用这些比较操作符时, 会产生一些混淆.
例如我们定义一个使用 <= 操作符的箭头函数
const negativeToZero = number => number <= 0 ? 0 : number;
同一行上的两个符号 => 和 <= 的存在会引起误解.
为了清楚地将胖箭头与比较操作符区分开, 我们可以使用圆括号:
const negativeToZero = number => (number <= 0 ? 0 : number);
第二个选项是使用更长的形式来定义箭头函数:
- const negativeToZero = number => {
- return number <= 0 ? 0 : number;
- };
这些重构消除了胖箭头符号和比较操作符之间的混淆.
第 3 个实践:
如果箭头函数包含操作符 > , < , <= 和 >= , 一个好的做法是将表达式包装成一对括号, 或者故意使用更长的箭头函数形式.
4. 构造普通对象
在内联箭头函数中使用对象字面量会触发语法错误:
- const array = [1, 2, 3];
- // throws SyntaxError!
- array.map(number => {
- 'number': number
- });
JS 认为花括号是代码块, 而不是对象文字.
将对象字面量加上一对括号即可解决此问题:
- const array = [1, 2, 3];
- // Works!
- array.map(number => ({
- 'number': number
- }));
如果对象字面量有很多属性, 我们可以使用换行, 同时仍然保持箭头函数内联
- const array = [1, 2, 3];
- // Works!
- array.map(number => ({
- 'number': number
- 'propA': 'value A',
- 'propB': 'value B'
- }));
第 4 个实践:
在内联箭头函数中使用对象时, 把改对象包装在一对括号中.
5. 注意过多的嵌套
箭头函数的语法很短, 很好. 但是, 副作用是, 当许多箭头函数嵌套时, 它可能是晦涩难懂.
我们考虑以下情况. 单击按钮后, 启动对服务器的请求, 响应准备就绪后, 将各项记录到控制台:
- myButton.addEventListener('click', () => {
- fetch('/items.json')
- .then(response => response.JSON());
- .then(JSON => {
- JSON.forEach(item => {
- console.log(item.name);
- });
- });
- });
这里有三层箭头函数的嵌套, 需要花时间和精力来了解代码的作用.
为了提高嵌套函数的可读性, 第一种方法是引入每个包含箭头函数的变量, 该变量应简明地描述函数的功能.
- const readItemsJson = JSON => {
- JSON.forEach(item => console.log(item.name));
- };
- const handleButtonClick = () => {
- fetch('/items.json')
- .then(response => response.JSON());
- .then(readItemsJson);
- };
- myButton.addEventListener('click', handleButtonClick);
重构将箭头函数提取到变量 readItemsJson 和 handleButtonClick 中. 嵌套级别从 3 减少到 2. 现在, 我们可以更轻松地了解脚本的功能.
更好的是, 可以使用 async/await 语法重构整个函数, 这是解决函数嵌套的一个很好的方法:
- const handleButtonClick = async () => {
- const response = await fetch('/items.json');
- const JSON = await response.JSON();
- JSON.forEach(item => console.log(item.name));
- };
- myButton.addEventListener('click', handleButtonClick);
第 5 个实践:
避免箭头函数过多的嵌套, 好的做法是通过将箭头函数提取为独立函数, 或者尽可能使用 async/await 语法.
6. 总结
JS 中的箭头函数是匿名的. 为了使调试更高效, 一个好的实践是使用变量来保存箭头函数, 这允许 JS 推断函数名.
当函数主体具有一个表达式时, 嵌入式箭头函数非常方便.
操作符 > , < , <= 和>= 看起来类似于胖箭头 => , 在内联箭头函数中使用这些操作符时必须小心.
对象字面量语法 {prop:'value'} 与代码块 {} 相似. 因此, 当将对象字面量放置在嵌入式箭头函数中时, 需要将其包装在一对括号中: ()=>({prop:'value'}) .
最后, 函数的过度嵌套模糊了代码意图. 减少箭头函数嵌套的一个好方法是将它们提取到变量中. 或者, 尝试使用更好的特性, 如 async/await 语法.
对于箭头函数, 你还有什么建议, 欢迎留言讨论.
代码部署后可能存在的 BUG 没法实时知道, 事后为了解决这些 BUG, 花了大量的时间进行 log 调试, 这边顺便给大家推荐一个好用的 BUG 监控工具 Fundebug .
来源: http://news.51cto.com/art/202002/610593.htm