本文翻译自 I Bet You Don't Use These JavaScript Tricks and Practices,作者:Nirjal Paudel, 略有删改。
本文推荐一些实际开发中的JavaScript技巧和实践,希望能对你有所帮助,有兴趣的可以看看原文。
1.使用FlatMap
JavaScript
中的Flat Map是一个很好用的方法。Flat Map实质上是将映射技术和过滤数组技术结合在了一起。更建议你使用flatMap()
而不是filter()
和map()
的组合。
FlatMap只执行一次,不会生成中间数组,但是
filter()
和map()
的组合会生成一个中间数组。
js
// using filterAndMap
console.time("filterAndMap")
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const squaredOddNumbers = numbers
.filter(num => num % 2 !== 0)
.map(num => num * num)
console.log(squaredOddNumbers); // [1, 9, 25, 49, 81]
console.timeEnd("filterAndMap")
以下是打印代码运行的执行时间:
js
console.time("filterAndMap")
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const squaredOddNumbers = numbers.flatMap(num =>
num % 2 !== 0 ? [num * num] : []
);
console.log(squaredOddNumbers); // [1, 9, 25, 49, 81]
console.timeEnd("filterAndMap")
以下是打印代码运行的执行时间:
通过两者运行的时间即可很容易的看出差距。
2. 数组排序
数组方法是一些帮助我们与数组进行交互的最重要的方法之一。在 JavaScript 中有许多数组方法可用。最常用的数组方法包括 .filter()
、.find()
、.map()
和 .reduce()
。它们可以组合在一起产生一些很不错的效果,例如以下代码:
js
const numbers = [9, 3, 6, 4, 8, 1, 2, 5, 7];
numbers
.sort((a, b) => a - b)
.filter((n) => n % 2 !== 0)
.map((n) => n ** 3);
程序上面看起来不错,对吧?但是有一个问题。注意我们先对数字进行了排序,然后再应用过滤器。如果我们先应用过滤器,然后排序,最后再求幂,就可以执行更少的操作。这样我们可以优化一组由点运算符连接的数组方法。
上面的最佳代码是:
js
const numbers = [9, 3, 6, 4, 8, 1, 2, 5, 7];
numbers
.filter((n) => n % 2 !== 0)
.sort((a, b) => a - b)
.map((n) => n ** 3);
3.不经常使用的 reduce 函数
我见过很多前端开发者在处理这个问题时遇到困难。比如像react-charts
这样的包要求以对象结构传递数据,但实际上react-charts
的实现要求以键分组的格式传递数据,所以我见过大多数开发者使用.forEach()
方法或错误地使用map()
方法来处理这个问题,就像下面这样:
js
fetch("https://jsonplaceholder.typicode.com/todos/")
.then(res=>res.json())
.then(todos=>{
// using Map
const todosForUserMap = {};
todos.forEach(todo=>{
if (todosForUserMap[todo.userId]){
todosForUserMap[todo.userId].push(todo);
}else{
todosForUserMap[todo.userId] = [todo];
}
})
console.log(todosForUserMap)
})
这种方法很好,它使用了forEach
方法而不是map
方法。map
方法在这里明显不适用,因为它会在幕后会为每个元素创建一个数组。假设数组有1000个条目,那么在map
中将创建一个1000个条目的空数组,而在forEach
中不会创建这样的数组。
但我们不使用上面的两种方法,一个相当简洁和易读的方法是使用数组的 reduce
方法。优化后的代码如下:
js
fetch("https://jsonplaceholder.typicode.com/todos/")
.then(res=>res.json())
.then(todos=>{
// using Map
const todosForUserMap = todos.reduce((accumulator, todo)=>{
if (accumulator[todo.userId]) accumulator[todo.userId].push(todo);
if (!accumulator[todo.userId]) accumulator[todo.userId] = [todo];
return accumulator;
},{})
console.log(todosForUserMap)
})
这样不会创建任何不必要的数组,代码更干净且更好用。它与forEach()
类似,但建议用下面的方式,因为它更清晰,更容易理解。
4.未充分使用原生JavaScript类
JavaScript自带很多原生javascript类,可以帮助你很容易地创建/实例化URL,Header等。以下代码可能比较常见,有人会试图像这样在URL中处理参数。
js
async function getUrl(userId, limit, category){
return `https://fakestoreapi.com/products${category ? `/category/${category}` : ""}${limit ? Number(limit):""}${userId? Number(userId):""}`;
}
上面的代码看着很混乱,很可能会中断,每次都需要你在最后添加一些规则,添加一些其他参数,通过使用本地类,如URL,我们可以改进更好的代码。改进的代码看起来像下面这样。
js
function constructURL(category, limit, userId) {
const baseURL = "https://fakestoreapi.com/products";
const url = new URL(baseURL);
const params = new URLSearchParams();
if (category) url.pathname += `/category/${category}`;
if (limit) params.append('limit', Number(limit).toString());
if (userId) params.append('userId', Number(userId).toString());
url.search = params.toString();
return url.toString();
}
这样就可以在同一个文件中处理复杂的URL构建条件。这里的URL对象遵循建造者模式(BuilderPattern),它是你可以在代码中实现的许多设计模式之一,可以将复杂的逻辑放在一个单独的地方处理,同时也提高了代码可读性。
最后
这些JavaScript技巧和实践旨在提高开发效率、增强代码质量和性能优化。希望对你有用且能从中获得一些启发,并应用到实际项目中。
看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~
专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)