我敢打赌你不会使用这些 JavaScript 技巧

87 阅读4分钟

image.png

今日没有废话,直接上干货~

  1. 使用FlatMap

在JavaScript中,Flat Map是一个很不错的API。Flat Map本质上将map和filter数组方法的技巧结合在一起。我建议你使用flatMap()而不是filter()和map()的组合。

FlatMap在单次遍历中执行,并且不会产生中间数组,但是filter()和map()的组合会产生一个中间数组。

// 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")

使用过滤器和映射

image.png

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")

使用FlatMap image.png

2. 数组方法的顺序

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

// a array methods that sorts only the array 
// for only odd numbers and raises it by power of 3
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];

// a array methods that sorts only the array
// for only odd numbers and raises it by power of 3
numbers
  .filter((n) => n % 2 !== 0)
  .sort((a, b) => a - b)
  .map((n) => n ** 3);

3. 没有充分利用减少的方法。

比如,像 react-charts 这样的包要求以对象结构的方式提供数据,但是 react-charts 的实现要求以键分组的格式提供数据,所以我看到大多数开发使用 .forEach() 方法或者错误地使用 map() 方法,就像这样。

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个null条目的数组,而在forEach()中不会创建这个数组。

与上述方法不同,一个更为简洁和易读的方法是使用数组的reduce方法。上述代码现已经过修正

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 开发者很少使用的代码片段,只有在编码面试中才会涉及到它们的知识。在数据获取的场景中,数据库或者 API 中的数据可能是无限的,而且数量庞大,你需要在前端进行流式处理。在这种情况下,React 中最常用的解决方案就是无限加载方案。

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

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

async function *fetchProducts(){
  while (true){
    const productUrl = "https://fakestoreapi.com/products?limit=2";
    const res = await fetch(productUrl)
    const data = await res.json()
    yield data;
    // manipulate the UI here like 
    // or save it in DB or somewhere else
    // use it as a side effect place
    // even if some condition matches, break the flow
  }
}

async function main() {
  const itr = fetchProducts();
  // this should be called based on user interaction
  // or other tricks as you don't want inifinite loading.
  console.log( await itr.next() );
}

return 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,我们可以改进我们的代码。改进后的代码如下所示。

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对象遵循了建造者模式,它是你可以在代码中实现的众多设计模式之一,可以将复杂逻辑隐藏在一个单独的位置,并提高代码的可读性。