原文连接:5 Best Practices to Write Quality Arrow Functions, by Dmitri Pavlutinjavascript
箭头函数值得流行。它语法简洁,函数体里的 this
是词法环境提供的,很是适合用做回调函数。java
本篇文章,你讲学习到 5 个 编写高质量箭头函数的最佳实践。json
JS 中的箭头函数是 匿名的(anonymous):即函数的 name
属性是个空字符串 ''
。服务器
( number => number + 1 ).name; // => ''
复制代码
匿名函数在调试会话(debug session)或调用栈分析(call stack analysis)时被标记为 anonymous
。不幸的是,匿名函数并不能为调试程序带来有用的线索。session
下面展现了执行匿名函数代码时的一个调试会话界面:async
右侧的调用栈中(call stack)中包含两个被标记为 anonymous
的函数。这类调用栈信息没法提供任何有用的线索。函数
幸运的是,箭头函数名推理(function name inference,ES2015 提供的一个特性)能够在某些条件下检测到函数名称。名称推理的原理是 JS 能够从其语法位置肯定箭头函数名称:例如,从保存函数对象的变量名称中得到。学习
咱们来看看,箭头函数名推理的例子:fetch
const increaseNumber = number => number + 1;
increaseNumber.name; // => 'increaseNumber'
复制代码
increaseNumber
是保存箭头函数对象的一个变量,JS 认为 'increaseNumber'
能够做为箭头函数的名字,原始箭头函数就使用了这个名字。ui
“一个最佳实践是使用函数名推理来命名箭头函数。”
如今再来看看使用了名称推理的调试会话界面:
由于箭头函数具备名称,因此调用堆栈能提供正在执行的代码的更多信息:
handleButtonClick
代表发生了一个点击事件increaseCounter
增长了计数器变量的值行内函数(inline function)是指仅包含一个表达式的函数。我喜欢箭头函数的行内书写方式。
举个例子:
const array = [1, 2, 3];
array.map((number) => {
return number * 2;
});
复制代码
当箭头函数里只有一个表达式的时候,咱们不使用这种长形式(logn form),而是把括号 {}
和 return
删掉。
const array = [1, 2, 3];
array.map(number => number * 2);
复制代码
这就是个人建议:
“当箭头函数只包含一个表达式的时候,一种好的作法是使用箭头函数的行内形式。”
比较运算符 >
、<
、<=
和 >=
跟胖箭头 =>
(定义箭头函数时使用的)很像。
当这些比较运算符跟行内箭头函数一块儿使用的时候,会有点混乱。
举个例子:
const negativeToZero = number => number <= 0 ? 0 : number;
复制代码
一行里的 =>
和 <=
容器产生误导。
为了清楚地将胖箭头与比较运算符区分开,第一种选择是将表达式包装在一对括号中:
const negativeToZero = number => (number <= 0 ? 0 : number);
复制代码
第二个选择是故意使用箭头函数的长写法形式:
const negativeToZero = number => {
return number <= 0 ? 0 : number;
};
复制代码
重构以后的代码能够消除胖箭头与比较运算符之间的混淆。
若是箭头函数中包含使用
>
、<
、<=
、>=
运算符的表达式,一个好的办法是将表达式包装在一对括号中,或者使用箭头函数的长写法形式。
行内箭头函数中的对象字面量会触发语法错误:
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'
}));
复制代码
个人建议:
“在行内箭头函数中使用时,将对象字面量包装在一对括号中。”
箭头函数的语法很短、很好。 但反作用是,当过多嵌套箭头函数使用时,代码可能就变得晦涩难懂了。
让咱们考虑如下状况——单击按钮,将发起一个对服务器的请求,响应准备就绪后,将返回数据记录在控制台:
myButton.addEventListener('click', () => {
fetch('/items.json')
.then(response => response.json())
.then(json => {
json.forEach(item => {
console.log(item.name);
});
});
});
复制代码
箭头函数是 3 级嵌套的。为了看懂这样的代码,须要花些时间和精力。
为了提升嵌套函数的可读性,第一种方法是将每一个箭头函数保存在一个变量中。该变量应简明地描述函数的功能。
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);
复制代码
个人建议:
经过将箭头函数保存在变量中的方式,能够避免代码的过多嵌套;同时,使用
async
/await
语法,也能够避免代码的过多嵌套。
JS 中的箭头函数是匿名的。为了使调试高效,一个好的实践是使用变量来保存箭头函数。如此,就能使用箭头函数名推理特性了。
当函数主体只有一个表达式时,使用行内箭头函数很是方便。
比较运算符 >
、<
、<=
和 >=
跟胖箭头 =>
很像,使用行内箭头函数时,能够将表达式包装在括号中帮助区分。
行内箭头函数会把对象字面量语法 { prop: 'value' }
外的 {}
认做是代码块。所以,在行内箭头函数中使用对象字面量时,须要使用括号包装一下:() => ({ prop: 'value' })
。
最后,过多的箭头函数嵌套会掩盖代码意图。一种办法是将箭头函数提取到变量中。或者尝试使用更好的特性,例如 async
/await
语法。
(正文完)
广告时间(长期有效)
我有一位好朋友开了一间猫舍,在此帮她宣传一下。如今猫舍里养的都是布偶猫。若是你也是个爱猫人士而且有须要的话,不妨扫一扫她的【闲鱼】二维码。不买也没关系,看看也行。
(完)