【问题标题】:Pass `Array.prototype.includes` to callback without wrapping it in an anonomous function?将`Array.prototype.includes`传递给回调而不将其包装在匿名函数中?
【发布时间】:2021-02-19 19:25:31
【问题描述】:

为什么我需要将animals.includes 包装在一个匿名函数中以使以下 ES6 js 代码按预期工作?

const animals = ["ape", "dog", "pig"]
const nouns = ["car", "planet", "apple", "dog"]

const hasPulse = nouns.some((n) => animals.includes(n))

console.log(`Heartbeat ${hasPulse ? '' : 'not '}detected!`)

如果我打开animals.includes,它会抛出一个类型错误。

// this fails with TypeError: can't convert undefined to object
const hasPulse = nouns.some(animals.includes)

【问题讨论】:

    标签: javascript ecmascript-6 callback


    【解决方案1】:

    你可以不服用

    const hasPulse = nouns.some(Array.prototype.includes, animals);
    

    带有thisArgs,但不幸的是Array#includes带有第二个参数fromIndex,它被索引传递并破坏了想要的结果。

    【讨论】:

      【解决方案2】:

      我认为这是一个上下文问题,您应该将包含函数绑定到名词数组,以使其按您希望的方式工作。您拥有的代码未按预期工作的原因是,当您将包含函数传递给 some 时,它​​不会在数组上执行(这要么未定义,要么设置为浏览器中的窗口对象)。这是工作示例

      const animals = ["ape", "dog", "pig"]
      const nouns = ["car", "planet", "apple", "dog"]
      
      const hasPulse = nouns.some(animals.includes.bind(nouns))
      
      console.log(`Heartbeat ${hasPulse ? '' : 'not '}detected!`)

      【讨论】:

      • “试试这个”不是回答问题的好方法,即使您发布了工作代码。您应该解释问题是什么以及您的代码如何解决它。
      • @ScottMarcus 我已经更新了我的答案并包含了更多细节
      • 应该是.bind(animals)
      • @Barmar if you .bind(animals) 我认为它不能正常工作。名词中有一只狗,但不会被发现
      • 但animals 是您要使用includes() 搜索的数组。
      【解决方案3】:

      这与 Javascript 方法如何“知道”它在调用时附加到哪个对象有关:它的 this 引用。

      includes 可以这样实现(假设示例):

      Array.prototype.includes = function includes(couldBeMember) {
        for (const member of this) {
          if (member === couldBeMember) {
            return true;
          }
        }
        return false;
      }
      

      animals.includes(argument) 将argument 传递给Array.prototype.includes,但在通话期间还将其this 设置为animals。仅引用animals.includes 并将其传递到其他地方,与传递Array.prototype.includes 没有什么不同;如果它最终被调用(在some 内部)而不引用animals,则不会将animals 设置为其this。

      要创建一个函数includes“记住”它的this是animals,无论函数本身传递到哪里,你都必须将bind它传递给animals:animals.includes.bind(animals)(或Array.prototype.includes.bind(animals) 或 [].includes.bind(animals))。

      const animals = ["ape", "dog", "pig"]
      const nouns = ["car", "planet", "apple", "dog"]
      
      const hasPulse = nouns.some([].includes.bind(animals))
      

      这并不比仅使用 lambda 更干净,但希望能回答您的问题。

      如果你喜欢这个想法但又想清理它,你可以创建一个独立的 bind 来做这样的事情:

      function bind(self, method, ...args) {
        return self[method].bind(self, ...args);
      }
      
      const hasPulse = nouns.some(bind(animals, "includes"))
      

      (至少还有一个建议是创建一个执行等效绑定的运算符,例如animals::includes,但我不相信这已经完成,但我最后检查了一下,所以语法可能会改变或者它可能不会结束支持。)

      【讨论】:

        【解决方案4】:

        这是因为Array.prototype.some() 如何调用它的回调与Array.prototype.includes() 如何期望参数之间不兼容。

        [].includes()的完整定义是:

        [].includes(thingToSearch, startSearchFrom);
        

        例如,如果你这样做:

        [1,2,3,4,5].includes(1,3); // false
        

        即使数组清楚地包含1,它也会返回false。这是因为您告诉它从元素3 开始搜索,所以.includes() 只查看了4 和5,找不到1。

        [].some()的完整定义是:

        [].some(function (item, index, theArray) {}, this);
        

        所以.some() 会将当前项目的索引传递给您传递给它的回调。例如,如果你这样做:

        [10,20,30,40,50].some((x,y) => y == 2); // 30
        

        它会返回30,因为他第一次.some() 循环遍历数组,它通过10 到x 和0 到y。第二次通过20 到x 和1 到y。第三次y 将是2,所以y == 2 为真,所以它返回true 的值,即30。

        现在您可以看到.some() 作为第二个参数传递的内容和.includes() 期望作为第二个参数传递的内容具有不同的含义。

        .some() 方法将传递循环索引,而 .includes() 方法期望第二个参数告诉它从哪里开始搜索。

        如果你这样做:

        const animals = ["ape", "dog", "pig"];
        const nouns = ["car", "planet", "apple", "dog"];
        
        nouns.some(animals.includes);
        
        1. .. 它会在ape,dog,pig 中搜索car,

        2. .. 然后它会在 dog,pig 中搜索 planet(记住索引现在是 1,所以你告诉 .includes() 忽略 ape)

        3. .. 然后它会在pig 中搜索apple(索引现在是2,所以.includes() 会忽略ape 和dog)

        4. .. 然后它会在一个空数组中搜索dog,当然它不会找到。

        当然,您可能希望通过某种算法来执行此操作。但我不认为这是你期望发生的。

        【讨论】:

          【解决方案5】:

          some() 方法测试数组中的一个或多个元素是否通过了在提供的函数中实现的测试,并返回一个指示结果的布尔值。

          const hasPulse = nouns.some((n) => animals.includes(n))
          

          第二种选择不起作用。 Array.includes 使用从调用函数接收的第二个参数(fromIndex)作为索引,并省略该函数要检查的值。

          【讨论】:

          • 它与 op 的第一种方法有什么不同?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-04-13
          • 1970-01-01
          • 2018-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多