【问题标题】:Combining forEach() with early returns将 forEach() 与早期返回相结合
【发布时间】:2019-04-27 05:44:49
【问题描述】:

我的问题

ESLint airbnb 策略不允许for...of 循环迭代,而更喜欢forEach((element) => { code });。但是,该循环的内部返回被吞没了——它们被视为匿名函数的returns,而不是包含该循环的函数。

代码

原创

工作,但打破eslint-config-airbnb

const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator1() {
  const wordlist = [];
  for (const word of words) {
    if (word.length >= MIN_WORD_SIZE) {
      wordlist.push(word);
    }
    if (wordlist.length >= MAX_WORDS) {
      return wordlist;
    }
  }
  return wordlist;
}

console.log(NestedIterator1());

备选方案 1:迭代数组索引

有效,但样式已过时,我必须按索引手动分配值。

const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;


function NestedIterator2() {
  const wordlist = [];
  for (let i = 0; i < words.length; i += 1) {
    const word = words[i];
    if (word.length >= MIN_WORD_SIZE) {
      wordlist.push(word);
    }
    if (wordlist.length >= MAX_WORDS) {
      return wordlist;
    }
  }
  return wordlist;
}


console.log(NestedIterator2());

备选方案 2:使用 forEach

遵守风格指南,但不起作用 - 内部返回被视为来自匿名函数的返回,而不是 NestedIterator3

const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
  const wordlist = [];
  words.forEach((word) => {
    if (word.length >= MIN_WORD_SIZE) {
      wordlist.push(word);
    }
    if (wordlist.length >= MAX_WORDS) {
      return wordlist;
    }
  });
  return wordlist;
}

console.log(NestedIterator3());

我的问题

函数如何在允许提前返回并避免索引和for..of 迭代的同时对数组进行迭代?

【问题讨论】:

  • 真的有必要吗?我遵从实际的reason in the style guide“为什么?这强制执行我们的不可变规则。处理返回值的纯函数比副作用更容易推理。”。虽然我同意避免可变性很重要,但说for..infor..of 容易崩溃,这有点牵强。因此,该规则似乎有问题,可能应该被覆盖
  • 使用try .. catchforEach 回调中抛出异常会像break 一样工作,但我相信它比eslint 警告或每个文件抑制规则更令人困惑
  • @skyboyer 同意。这不是一个“独特”的问题,在Short circuit Array.forEach like calling break 之前肯定有人问过。我宁愿 OP 通常自己承认副本。当然看不出怎么会有与已经存在的答案完全不同的答案。

标签: node.js short-circuiting early-return


【解决方案1】:

一种选择是使用reduce,它非常灵活,可以在其他迭代方法不够用的许多情况下使用 - 如果累加器的长度小于@987654323,则只有push 用于累加器@的单词长度就足够了:

const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
  return words.reduce((wordlist, word) => {
    if (wordlist.length < MAX_WORDS && word.length >= MIN_WORD_SIZE) {
      wordlist.push(word);
    }
    return wordlist;
  }, []);
}

console.log(NestedIterator3());

尽管如此,上述方法确实 迭代了所有指标——它实际上并没有提前返回,它只是在满足结束条件后在以后的迭代中不做任何事情。如果你想真正跳出迭代器,你可以改用.some,虽然它更不纯,而且代码的意图也不太清楚IMO:

const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
  const wordlist = [];
  words.some((word) => {
    if (word.length >= MIN_WORD_SIZE) {
      wordlist.push(word);
    }
    return wordlist.length === MAX_WORDS;
  }, []);
  return wordlist;
}

console.log(NestedIterator3());

对于这个特殊的例子,您还可以使用filter,后跟slice

const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
  return words
    .filter(word => word.length >= MIN_WORD_SIZE)
    .slice(0, MAX_WORDS)
}

console.log(NestedIterator3());

这当然看起来更优雅,但.filter 必须首先迭代数组中的所有项目,因此与reduce 有相同的问题(没有短路发生) - 此外,那些两个链式方法仅代表可能希望短路数组迭代的情况的子集。

【讨论】:

    猜你喜欢
    • 2014-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多