【问题标题】:Why does Array.filter(Number) filter zero out in JavaScript?为什么 Array.filter(Number) 在 JavaScript 中过滤零?
【发布时间】:2018-12-25 06:52:06
【问题描述】:

我正在尝试从数组中过滤掉所有非数字元素。使用 typeof 时,我们可以看到所需的输出。但是使用 Number,它会过滤掉零。

这是示例(在 Chrome 控制台中测试):

[-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(Number)
// Which output with zero filtered out:
[-1, 1, 2, 3, 4]  // 0 is filtered

如果我们使用 typeof,它不会过滤零,这是预期的。

// code
[-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(n => typeof n === 'number')
// output
[-1, 0, 1, 2, 3, 4, 0]

我的问题:

  1. 'Number' 和 'typeof' 方法有什么区别?

  2. 数字过滤零,但“数字”本身包含零,这让我很困惑。

【问题讨论】:

    标签: javascript numbers typeof


    【解决方案1】:

    因为0 是javascript 中众多falsy 值之一

    所有这些条件都将发送到else 块:

    if (false)
    if (null)
    if (undefined)
    if (0)
    if (NaN)
    if ('')
    if ("")
    if (``)
    

    来自Array.prototype.filter() 文档:

    filter() 为数组中的每个元素调用一次提供的callback 函数,并构造一个包含所有值的新数组,回调为其返回一个强制为真的值

    在您的情况下,回调函数是Number。所以你的代码相当于:

    [-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(a => Number(a)) 
    
    // Number(0) -> 0
    // Number(Number(0)) -> 0
    // Number('') -> 0
    // Number('test') -> NaN
    

    filter 函数选择truthy 值(或强制为true 的值)时,将忽略返回0NaN 的项目。所以,它返回[-1, 1, 2, 3, 4]

    【讨论】:

    • 请注意,new Boolean(false) 是真值,还有一个空对象 ({}) 和一个空数组 ([])。
    【解决方案2】:

    为了防止 falsy 零过滤,您可以使用另一个回调来仅获取数值:Number.isFinite

    console.log([-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(Number.isFinite))

    【讨论】:

    • 请注意,与 Number('1') 返回一个真实值 1 不同,Number.isFinite('1') 返回 false
    【解决方案3】:

    预期行为

    这种行为并不是使用 Number 作为过滤函数所独有的。简单地返回 0 值的过滤器函数也会将其从列表中删除。

    var a = [-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(v => v)
    console.log(a); // [-1, 1, 2, 3, 4, "test"]

    这是因为Number 并不是一个特定的过滤器函数,它主要是一个类型转换函数(和一个类构造函数,但不是很有用)。所以当一个数字(如0)被传递给Number时,它只会返回那个数字。

    Array.prototype.filter 删除 falsy 的值。在 JavaScript 中,以下内容是虚假的,因此被 filter 删除。

    false
    null
    undefined
    0
    NaN
    ''
    ""
    ``
    

    (出于复杂的向后兼容性原因,MDN goes intodocument.all 尽管是一个对象,但在许多浏览器中也是虚假的,但这是一个旁注)

    【讨论】:

    • 使用 Number.isFinite 代替 Number 将在代码中更加语义化。
    【解决方案4】:

    零是一个虚假值。 typeof 总是返回一个布尔值。返回数字 0 时,是返回测试,因此返回为 false,因此过滤掉数字 0。

    【讨论】:

      【解决方案5】:

      这是因为 0 是一个 falsy 值,它返回 false,任何返回 false 到 filter 函数的东西都会被过滤出新数组。

      文档

      https://developer.mozilla.org/en-US/docs/Glossary/Falsy

      【讨论】:

        【解决方案6】:

        当您在过滤器中使用 Number 时,实际上它是将 Array 的每个项目传递给 Number 构造函数,如果是字符串或 0 Number 将返回 NaN 或 0 并且它们都是 false 所以过滤器正在过滤掉它们

        而当您使用 typeof 时,0 具有“数字”类型,因此它返回 true,并且 filter 方法不会将其过滤掉

        【讨论】:

          【解决方案7】:

          为了防止过滤falsy 零,您可以使用另一个回调来仅获取数值:Number.isFinite

          console.log([-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(Number.isFinite))

          【讨论】:

            【解决方案8】:

            这种行为的原因是 0, null, undefined, NaN 在 JavaScript 中相当于 false 所以,在第一种情况下:

            [-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(Number);
            

            当在过滤器中使用 Number 作为参数之一时,它返回数字本身。因此,当传递 0 时,它返回 0,javascript 将其理解为 false。所以,它返回

            [-1, 1, 2, 3, 4]
            

            所以为了安全起见,建议使用Number.isFinite 而不是Number

            [-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(Number.isFinite);
            

            给出与

            相同的结果
            [-1,0,1,2,3,4, Number(0), '','test'].filter(n=> typeof n === 'number');
            

            愿意。

            【讨论】:

              【解决方案9】:

              这是另一个示例,展示了如何从数字数组中删除多个索引,并处理 0:

              const array = [0,1,2,3,4,5,6,7,8,9]
              console.log('init', array)
              
              const indicesToDel = [2, 3, 5, 9]
              console.log('indices to del', indicesToDel)
              
              let result = array.filter( (item, index) => !indicesToDel.includes(index) ? Number.isFinite(item) : false )
              console.log('result', result)

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-10-22
                • 2020-05-09
                • 2011-01-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-06-03
                相关资源
                最近更新 更多