探索未知:你可能还未尝试的 JavaScript 技巧

发表时间: 2023-09-15 16:15

转载说明:原创不易,未经授权,谢绝任何形式的转载

在现代前端开发中,JavaScript是不可或缺的一部分。然而,尽管我们日常使用它来构建强大的Web应用程序,但JavaScript仍然有许多强大的功能和技巧,可能仍然未被广泛利用。本文将分享一些你可能还没有使用的JavaScript技巧,这些技巧可以让你的代码更加高效和易于维护。让我们一起来看看这些技巧吧!

1、使用FlatMap

在JavaScript中,FlatMap是一种很棒的技术,你可以在这里学习。FlatMap本质上将map和filter数组方法的技巧结合在一起。我建议你使用flatMap()而不是filter()和map()的组合。

FlatMap采用单次遍历,不生成中间数组,而filter()和map()的组合则会生成中间数组。

// 使用filter和map方法来筛选奇数并计算它们的平方console.time("filterAndMap"); // 启动性能计时器const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];// 使用filter方法筛选出奇数const oddNumbers = numbers.filter(num => num % 2 !== 0);// 使用map方法计算奇数的平方const squaredOddNumbers = oddNumbers.map(num => num * num);console.log(squaredOddNumbers); // 输出平方后的奇数数组:[1, 9, 25, 49, 81]console.timeEnd("filterAndMap"); // 停止性能计时器并输出执行时间

// 启动性能计时器console.time("filterAndMap");// 原始数组const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];// 使用 flatMap 方法筛选出奇数并计算其平方const squaredOddNumbers = numbers.flatMap(num =>     num % 2 !== 0 ? [num * num] : []);// 输出平方后的奇数数组:[1, 9, 25, 49, 81]console.log(squaredOddNumbers);// 停止性能计时器并输出执行时间console.timeEnd("filterAndMap");

2、数组方法的顺序

数组方法是帮助我们与数组进行交互的一些最重要的方法。在JavaScript中有许多数组方法。最受欢迎的数组方法有.filter()、.find()、.map()、.reduce()。它们可以合并在一起产生一些精彩的模式,就像这些一样。

// 对原始数组进行升序排序numbers.sort((a, b) => a - b)// 筛选出数组中的奇数.filter((n) => n % 2 !== 0)// 计算奇数的立方值.map((n) => n ** 3);

一眼看上去,上面的程序看起来很不错,但是有一个大问题。注意我们是先对数字进行排序,然后再进行筛选的。如果我们先使用筛选,然后再排序,我们可以减少一些任务。这样,我们可以优化一组通过(.)链接的数组方法。以上的最佳代码是:

// 原始数组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() 方法,就像这样。

// 发送HTTP GET请求以获取位于指定URL的待办事项数据fetch("https://jsonplaceholder.typicode.com/todos/")  .then(res => res.json()) // 解析响应数据为JSON格式  .then(todos => {        // 使用Map数据结构来将待办事项按用户ID分组    const todosForUserMap = {}; // 创建一个空对象,用于存储按用户ID分组的待办事项    todos.forEach(todo => {      // 遍历待办事项数组,并根据用户ID将它们分组      if (todosForUserMap[todo.userId]) {        // 如果已存在具有相同用户ID的待办事项数组,则将当前待办事项添加到数组中        todosForUserMap[todo.userId].push(todo);      } else {        // 如果还没有该用户ID的待办事项数组,创建一个新的数组并添加当前待办事项        todosForUserMap[todo.userId] = [todo];      }    });    // 输出按用户ID分组的待办事项数据    console.log(todosForUserMap);  })

这个方法很好,因为它使用了forEach方法而不是map方法。显然,map方法在这里不适用,因为它会为每个元素创建一个数组。假设数组有1000个条目,那么在map中将创建一个包含1000个null条目的数组,而在forEach()中不会创建这个数组。

不使用上述任何方法,一个相当干净和易读的方法是使用数组的reduce方法,上述代码现已得到修正。

// 发送HTTP GET请求以获取位于指定URL的待办事项数据fetch("https://jsonplaceholder.typicode.com/todos/")  .then(res => res.json()) // 解析响应数据为JSON格式  .then(todos => {        // 使用Map数据结构来将待办事项按用户ID分组    const todosForUserMap = todos.reduce((accumulator, todo) => {      // 如果累加器中已经存在具有相同用户ID的条目,则将该待办事项添加到相应用户ID的数组中      if (accumulator[todo.userId]) accumulator[todo.userId].push(todo);      // 否则,在累加器中创建一个新的数组,并将待办事项添加到该数组中      if (!accumulator[todo.userId]) accumulator[todo.userId] = [todo];      return accumulator;    }, {}); // 初始累加器为空对象    // 输出按用户ID分组的待办事项数据    console.log(todosForUserMap);  })

这样做不会创建任何不必要的数组,更加简洁,更好使用。它与forEach()类似,但我建议使用这种方式,因为它更加简洁易懂。

使用生成器(Generators)

生成器和迭代器可能是那些 JavaScript 开发者很少使用的代码片段,只有在编码面试中才会涉及到。在数据获取的场景中,数据库或 API 中的数据可能是无限的,且数量庞大,你需要在前端进行流式处理。在这种情况下,React 中最常用的解决方案是无限加载方案。

面试题:你如何在Node.js服务器或纯JavaScript中实现类似无限加载的功能?

这就是迭代器真正有用的地方。不必将请求中的大量数据流式存储在本地存储或其他地方以供以后使用。这是使用异步生成器之一的方法。通过这种方式,我们可以解决JS中的无限加载问题。

// 异步生成器函数,用于获取产品数据async function *fetchProducts(){  while (true){    const productUrl = "https://fakestoreapi.com/products?limit=2"; // 定义产品数据的API URL,限制每次获取2个产品    const res = await fetch(productUrl); // 发送HTTP请求,等待响应    const data = await res.json(); // 解析响应数据为JSON格式    yield data; // 通过生成器返回数据    // 在此处可以操作用户界面(UI)    // 或将数据保存到数据库或其他地方    // 可以将其用作副作用的地方    // 即使某些条件满足,也可以中断数据流  }}async function main() {  const itr = fetchProducts(); // 调用fetchProducts()函数以获取产品数据的生成器对象  // 这应该根据用户交互或其他策略来调用  // 避免无限加载数据  console.log( await itr.next() ); // 输出生成器的下一个数据项}return main(); // 执行main()函数

5. 不使用原生的Javascript类

Javascript内置了一些原生的Javascript类,可以帮助您轻松创建/实例化URL、Headers等对象。我们可能会看到有人尝试像这样查询URL中的参数。

async function getUrl(userId, limit, category){  return `https://fakestoreapi.com/products${category ? `/category/${category}` : ""}${limit ? Number(limit):""}${userId? Number(userId):""}`;    }

上面的代码很混乱,很可能会出错,并且每次添加其他参数时都需要在最后添加一些规则。通过使用像URL这样的本地类,我们可以改进我们的代码。改进后的代码如下所示。

// 构建URL的函数,接受三个参数:category(类别)、limit(数量限制)、userId(用户ID)function constructURL(category, limit, userId) {  // 基础URL  const baseURL = "https://fakestoreapi.com/products";    // 创建一个 URL 对象  const url = new URL(baseURL);    // 创建一个用于存储查询参数的 URLSearchParams 对象  const params = new URLSearchParams();  // 如果传入了 category 参数,将其添加到路径中  if (category) url.pathname += `/category/${category}`;    // 如果传入了 limit 参数,将其添加为查询参数  if (limit) params.append('limit', Number(limit).toString());  // 如果传入了 userId 参数,将其添加为查询参数  if (userId) params.append('userId', Number(userId).toString());  // 将查询参数添加到 URL 中  url.search = params.toString();  // 返回构建完成的 URL 字符串  return url.toString();}

通过这种方式,您可以在同一个文件中处理复杂的URL构建条件。您知道吗,这里的URL对象遵循了建造者模式,它是您可以在代码中实现的许多设计模式之一,可以将复杂逻辑隐藏在一个单独的位置,并提高可读性。

结尾

正如我们在本文中所看到的,JavaScript是一个充满惊喜和创新的语言,拥有丰富的功能和技巧,可以帮助我们更好地处理数据和构建Web应用程序。从使用FlatMap来提高性能,到优化数组方法的顺序,再到利用reduce函数的威力,以及使用生成器来解决无限加载问题,以及更加优雅的处理URL构建,这些技巧都可以让你的代码更加优雅和高效。

无论你是初学者还是经验丰富的开发者,掌握这些技巧都将提升你的JavaScript编程技能。不断学习和探索新的方法是成为一名出色的开发者的关键。希望这些技巧能够帮助你更好地利用JavaScript的潜力,提高你的开发效率。愿你在编写JavaScript代码时收获更多的乐趣和成就感!

由于文章内容篇幅有限,今天的内容就分享到这里,文章结尾,我想提醒您,文章的创作不易,如果您喜欢我的分享,请别忘了点赞和转发,让更多有需要的人看到。同时,如果您想获取更多前端技术的知识,欢迎关注我,您的支持将是我分享最大的动力。我会持续输出更多内容,敬请期待。