【问题标题】:Reduce an array of objects to the unique strings found in a property shared by all objects (javascript)将对象数组减少为在所有对象共享的属性中找到的唯一字符串(javascript)
【发布时间】:2017-09-23 16:03:38
【问题描述】:

我编写了一个 javascript 函数,它成功地返回了 HTML 文档中使用的所有唯一类的数组。

const elements = document.getElementsByTagName('*');

let classesUsedInHtml = htmlCollection => {
  let uniqClassSelectors = [];
  Array.from(htmlCollection)
    .filter(element => element.classList.length > 0)
    .map(element =>
      element.classList.forEach(
        item =>
          uniqClassSelectors.includes(item)
            ? null
            : uniqClassSelectors.push(item)
      )
    );
  return uniqClassSelectors;
};

console.log(classesUsedInHtml(elements));

我想使用Array.prototype.reduce() 重构这个函数,并跳过定义变量uniqClassSelectors 的需要,但一直无法使其工作。

这是我的重构函数不起作用(返回accumulator is undefined)。在这方面,我经常被reduce() 绊倒。为什么accumulator 未定义?我在reduce() 函数中没有正确使用forEach() 吗?谁能在这里指出我正确的方向?谢谢!

let classesUsedInHtml = htmlCollection => {
  return Array.from(htmlCollection)
    .filter(element => element.classList.length > 0)
    .reduce((accumulator, element) => {
      return element.classList.forEach(
        classSelector =>
          accumulator.includes(classSelector)
            ? accumulator
            : accumulator.concat(classSelector)
      );
    }, []);
};

编辑:由于 Nina Scholz 的评论,从相关函数中删除了不必要的 map()

【问题讨论】:

  • 如果不取返回值,为什么要映射(在第一个代码中)?第二个不返回你想要的forEach。它只返回未定义的。
  • 好消息@NinaScholz。我将更新上面的问题功能。但这并不能解决根本问题。

标签: javascript arrays foreach


【解决方案1】:

我建议为最终的domTokenList 使用另一个内部累加器,并将外部accumulator 作为内部累加器acc2 的起始值。

let classesUsedInHtml = htmlCollection =>
    Array
        .from(htmlCollection)
        .filter(element => element.classList.length)
        .map(element => element.classList)
        .reduce((accumulator, domTokenList) =>
            domTokenList.reduce((acc2, classSelector) =>
                acc2.concat(acc2.includes(classSelector) ? [] : classSelector),
                accumulator
            ),
            []
        );

另一种解决方案是使用Set 来收集唯一的类选择器。

let classesUsedInHtml = htmlCollection =>
    [...Array
        .from(htmlCollection)
        .filter(element => element.classList.length)
        .map(element => element.classList)
        .reduce((acc1, domTokenList) =>
            domTokenList.reduce((acc2, classSelector) => acc2.add(classSelector), acc1),
            new Set)
    ];

【讨论】:

  • DOMTokenList 不是数组,但在其原型中确实有 forEach() 方法。因此,如果您添加 Array.from(domTokenList).reduce...,您的代码将有效。在数组上使用另一个 reduce() 是个好主意。但是您有任何见解如何使用forEach() 使其工作吗?
  • 正如我在 cmets 中所写,forEach 不会返回任何东西,可以使用。在这种情况下,您需要一个要消除的外部变量。所以要么取map,要么减少以获得新值。
  • 谢谢,在我发布之前没有看到您更新的 cmets。
【解决方案2】:

此解决方案的分步指南。注释(// ->)显示了这一步的结果,传递到下一步。

  1. 使用spread syntaxhtmlCollection转换为数组:

    [...htmlCollection] // -> [htmlElement, htmlElement, etc...]
    
  2. Array#map每个元素到一个类数组中(再次传播):

    [htmlElement, htmlElement, etc...].map(({ classList }) => [...classList])) // -> [[class, class, etc...], [class, class, etc...], etc...]
    
  3. 通过扩展到Array#concat 来展平子数组:

    [].concat(...[[class, class, etc...], [class, class, etc...]], etc...) // -> [class, class, class, etc...]
    
  4. 将数组转换为Set,并传回数组,得到唯一的类名:

    [...new Set([class, class, class, etc...])] // -> [class1, class2, class3, etc...]
    

const elements = document.getElementsByTagName('*');

const classesUsedInHtml = (htmlCollection) =>
    [...new Set( // get unique items and convert to array
      [].concat(... // concat all classes' arrays
        [...htmlCollection] // convert the collection to an array
        .map(({ classList }) => [...classList])) // get arrays of classes
      )
    ];
    
const result = classesUsedInHtml(elements);

console.log(result);
<div class="a c">
  <span class="a b"></span>
  <span class="b c"></span>
</div>

【讨论】:

  • 哇!我知道我不应该使用 cmets 表示“谢谢”,但我以前不知道 Set。使用扩展运算符真的很优雅,正是我正在寻找的那种方法。
  • 除了提供的 cmets 之外,谁能解释整个解决方案中发生了什么?
  • @BrianZ - 我已经添加了解决方案的逐步细分。
  • 非常有帮助,以至于您的指令从代码内部开始并流出。我从外向内阅读,迷路了。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-07
  • 2021-04-02
  • 2021-02-26
  • 1970-01-01
  • 2018-07-18
  • 2022-11-19
  • 2018-05-12
相关资源
最近更新 更多