【问题标题】:Javascript filter array of objects skip empty stringJavascript过滤对象数组跳过空字符串
【发布时间】:2019-06-04 19:02:11
【问题描述】:

我正在 NodeJS 中构建一个 REST API。我正在构建服务器端的分页、排序和过滤。

我有一个过滤器方法的简单实现。如果项目不包含任何空字符串,则此方法有效。但是,如果项目包含空字符串,.toString() 方法将失败,因为 item[filterBy]null

无法读取 null 的属性“toString”

如果项目包含空字符串,我如何更新过滤函数以简单地返回 true 以跳过比较操作?

  // Apply filter to array of objects
  // TODO: Empty strings breaks the filter
  items = items.filter(item =>
    item[filterBy].toString().trim().toLowerCase().indexOf(filterValue.toLowerCase()) !== -1)

【问题讨论】:

    标签: javascript filter


    【解决方案1】:

    要跳过包含空字符串的项目,试试这个:

    item[filterBy] && item[filterBy].toString()
    

    因此,您的代码将是:

    items = items.filter(item =>
    item[filterBy] && item[filterBy].toString().trim().toLowerCase().indexOf(filterValue.toLowerCase()) !== -1)
    

    【讨论】:

      【解决方案2】:

      大概是这样的:

      const filterValue = 'abc'
      const filterBy = 'name'
      const items = [
        {x: 1, name: 'abc'},
        {x: 2, name: 'def'},
        {x: 3, noname: 'def'},
        {x: 4, name: 'ABCDEF'},
      ]
      
      const newItems = items.filter(item =>
          !(filterBy in item) || item[filterBy].toString().trim().toLowerCase().indexOf(filterValue.toLowerCase()) !== -1)
          
      console.log(newItems)

      我们在这里所做的只是检查item 是否具有filterBy 属性。

      我不太清楚空字符串有什么问题。如果 item[filterBy] 未定义,您似乎很可能会收到该错误。这就是我们在这里检查的内容。

      如果您想跳过那些没有相关属性的内容,请从!(filterBy in item) || ... 切换到(filterBy in item) && ...

      【讨论】:

        【解决方案3】:

        也许:

        items = items.filter(
            item => item[filterBy] && item[filterBy].toString ?
                item[filterBy].toString().trim().toLowerCase().indexOf(filterValue.toLowerCase()) !== -1 :
                false
        )
        

        【讨论】:

          【解决方案4】:

          flatMap().map().flat() 的组合。它可以通过直接返回或不返回值来充当反向.filter()。有关详细信息,请参阅演示。

          const items = [{
            id: 'a',
            pn: 'B',
            desc: ''
          }, {
            id: 'b',
            pn: 'c',
            desc: 'd'
          }, {
            id: 'c',
            pn: 'k',
            desc: null
          }, {
            id: 'i',
            pn: 'k',
            desc: 2
          },, {
            id: 'o',
            pn: 'x',
            desc: 3
          }];
          
          // Utility function that returns a 'friendlier' value
          function clean(obj) {
            return obj == null ? false : Array.isArray(obj) ? obj : obj.constructor.name.toLowerCase() === "object" ? obj.toString().trim().toLowerCase() : typeof obj === "string" ? obj.toString().trim().toLowerCase() : Number(parseFloat(obj)) === obj ? obj : false;
          }
          
          // Filters by a single key and multiple values
          let filterKey = clean('desc');
          let filterVal = clean(['d', 2, 'f']);
          
          /* It returns each value in a sub-array an empty array will remove
          the value. In the final stage it flattens the array of arrays into a normal array
          */
          let list = items.flatMap(item => {
            return Object.entries(item).flatMap(([key, value]) => filterKey === (clean(key)) && [...filterVal].includes(clean(value)) ? [clean(value)] :[]);
          });
          
          console.log(list);

          【讨论】:

          • 这对let list = items.filter(item => filter.includes(item)) 有何改进?
          • 您可以链接三元组并在一行中根据需要解决任意多个条件。因此,如果您想返回除值之外的其他内容,这非常简单,您可以专门删除您喜欢的任何内容,没有问题。 ATM的要求很简单,但是展示另一种方式是不是错了?
          • 哦,这显然是一种有趣的技术,是一种将mapfilter 一次性结合起来的好方法。但由于这不是问题的直接答案,如果你要展示这种技术,我认为展示它做一些有用的事情会更好。您的示例使用items.filter 编写更简单。如果换成... ? [items.foo] : [],我想会清楚很多。
          【解决方案5】:

          链式过滤器是正确的,不会影响性能。

          const filterValue = 'John'
          const filterBy = 'name'
          const items = [
            {id: 1, name: 'John'},
            {id: 2, name: 'Doe, John'},
            {id: 3, ref: 1},
            {id: 4, name: 'No one'},
            {id: 5, name: null}
          ]
          
          let fItems = items.filter(item => item[filterBy])
                            .filter(item => item[filterBy].toString().trim().toLowerCase()
                               .indexOf(filterValue.toLowerCase()) !== -1)
             
          console.log(fItems);

          更新:修复了代码。

          【讨论】:

          • 这不是过滤器——您正在更改map 中的数据,而不是过滤它。
          • 谢谢你,@ScottSauyet。更新了我的答案。
          猜你喜欢
          • 2015-03-24
          • 2022-01-13
          • 1970-01-01
          • 2019-04-04
          • 2021-12-15
          • 2018-08-09
          • 1970-01-01
          • 2020-08-15
          • 2021-10-23
          相关资源
          最近更新 更多