编写高质量箭头函数的 5 个最佳实践

JS 中的箭头函数是 匿名的(anonymous):即函数的 name 属性是个空字符串 ‘’。
( number => number + 1 ).name; // => ‘’
复制代码匿名函数在调试会话(debug session)或调用栈分析(call stack analysis)时被标记为 anonymous。不幸的是,匿名函数并不能为调试程序带来有用的线索。
下面展示了执行匿名函数代码时的一个调试会话界面:

右侧的调用栈中(call stack)中包含两个被标记为 anonymous 的函数。这类调用栈信息无法提供任何有用的线索。
幸运的是,箭头函数名推理(function name inference,ES2015 提供的一个特性)可以在某些条件下检测到函数名称。名称推理的原理是 JS 可以从其语法位置确定箭头函数名称:例如,从保存函数对象的变量名称中获得。
我们来看看,箭头函数名推理的例子:
const increaseNumber = number => number + 1;

increaseNumber.name; // => ‘increaseNumber’
复制代码increaseNumber 是保存箭头函数对象的一个变量,JS 认为 ‘increaseNumber’ 可以作为箭头函数的名字,原始箭头函数就使用了这个名字。

“一个最佳实践是使用函数名推理来命名箭头函数。”

现在再来看看使用了名称推理的调试会话界面:

因为箭头函数具有名称,所以调用堆栈能提供正在执行的代码的更多信息:

handleButtonClick 表明发生了一个点击事件
increaseCounter 增加了计数器变量的值

  1. 尽可能使用行内形式
    行内函数(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);
复制代码这就是我的建议:

“当箭头函数只包含一个表达式的时候,一种好的做法是使用箭头函数的行内形式。”

  1. 胖箭头和比较运算符
    比较运算符 >、<、<= 和 >= 跟胖箭头 =>(定义箭头函数时使用的)很像。
    当这些比较运算符跟行内箭头函数一起使用的时候,会有点混乱。
    举个例子:
    const negativeToZero = number => number <= 0 ? 0 : number;
    复制代码一行里的 => 和 <= 容器产生误导。
    为了清楚地将胖箭头与比较运算符区分开,第一种选择是将表达式包装在一对括号中:
    const negativeToZero = number => (number <= 0 ? 0 : number);
    复制代码第二个选择是故意使用箭头函数的长写法形式:
    const negativeToZero = number => {
    return number <= 0 ? 0 : number;
    };
    复制代码重构之后的代码可以消除胖箭头与比较运算符之间的混淆。

如果箭头函数中包含使用 >、<、<=、>= 运算符的表达式,一个好的办法是将表达式包装在一对括号中,或者使用箭头函数的长写法形式。

  1. 正确返回对象字面量
    行内箭头函数中的对象字面量会触发语法错误:
    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’
}));
复制代码我的建议:

“在行内箭头函数中使用时,将对象字面量包装在一对括号中。”

  1. 避免过多的嵌套
    箭头函数的语法很短、很好。 但副作用是,当过多嵌套箭头函数使用时,代码可能就变得晦涩难懂了。
    让我们考虑以下情况——单击按钮,将发起一个对服务器的请求,响应准备就绪后,将返回数据记录在控制台:
    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 语法,也可以避免代码的过多嵌套。
http://www.kuyibu.com/product/84194099.html
http://www.kuyibu.com/product/84194096.html
http://www.kuyibu.com/product/84194095.html
http://www.kuyibu.com/product/84194093.html
http://www.kuyibu.com/product/84194088.html

总结
JS 中的箭头函数是匿名的。为了使调试高效,一个好的实践是使用变量来保存箭头函数。如此,就能使用箭头函数名推理特性了。
当函数主体只有一个表达式时,使用行内箭头函数非常方便。
比较运算符 >、<、<= 和 >= 跟胖箭头 => 很像,使用行内箭头函数时,可以将表达式包装在括号中帮助区分。
行内箭头函数会把对象字面量语法 { prop: ‘value’ } 外的 {} 认作是代码块。因此,在行内箭头函数中使用对象字面量时,需要使用括号包装一下:() => ({ prop: ‘value’ })。
最后,过多的箭头函数嵌套会掩盖代码意图。一种办法是将箭头函数提取到变量中。或者尝试使用更好的特性,例如 async/await 语法。

发布了86 篇原创文章 · 获赞 0 · 访问量 7193

猜你喜欢

转载自blog.csdn.net/chunzhenwang/article/details/104466600