【问题标题】:Why doesn't console.log work when passed as a parameter to forEach?为什么console.log 在作为参数传递给forEach 时不起作用?
【发布时间】:2012-03-27 04:56:00
【问题描述】:

这只是出于好奇,但你们中有人知道为什么这段代码不起作用吗?

[1, 2, 3, 4, 5].forEach(console.log);

// Prints 'Uncaught TypeError: Illegal invocation' in Chrome

另一方面,这似乎工作正常:

[1, 2, 3, 4, 5].forEach(function(n) { console.log(n) });

所以...?

【问题讨论】:

  • 确实如此。自己回答吧,我真是个白痴
  • 可以直接删除吗?这真的没那么有用=/
  • @PabloFernandez 我的意思是这个问题,但我猜有人喜欢它足以支持它所以也许它对某人毕竟有用......我永远不清楚支持是否来自真正找到问题的人有用,或者只是来自试图玩弄系统的回答者。
  • @GGG 我很好,但你认为这真的有必要吗?它得到了 2 个赞成...也许我们可以将它作为一个在 js 中谈论 bind 的问题的副本关闭它?
  • 最好关闭一个关于如何解决this 的问题......除了bind 之外,还有其他方法可以解决它。

标签: javascript arrays function foreach


【解决方案1】:

值得指出的是,console.log 的实现在行为上存在差异。在节点 v0.10.19 下,您不会收到错误消息;你只是看到这个:

> [1,2,3,4,5].forEach(console.log);
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]

这是因为forEach 的回调是一个三参数函数,它接受值、索引和数组本身。函数console.log 看到这三个参数并尽职尽责地记录它们。

但是,在 Chrome 浏览器控制台下,您会得到

> [1,2,3,4,5].forEach(console.log);
TypeError: Illegal invocation

在这种情况下,bind 工作:

 > [1,2,3,4,5].forEach(console.log.bind(console));
 1 0 [ 1, 2, 3, 4, 5 ]
 2 1 [ 1, 2, 3, 4, 5 ]
 3 2 [ 1, 2, 3, 4, 5 ]
 4 3 [ 1, 2, 3, 4, 5 ]
 5 4 [ 1, 2, 3, 4, 5 ]

但是还有另一种方法:注意forEach第二个参数采用this的值在回调中使用:

> [1,2,3,4,5].forEach(console.log, console)
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]

它适用于我的 Chrome 控制台和节点。当然,我确定您想要只是价值观,所以恐怕最好的解决方案确实是:

> [1,2,3,4,5].forEach(function (e) {console.log(e)});
1
2
3
4
5

节点的行为是否是一个错误,或者它只是利用了 console.log 不是 ECMA 指定的事实,这本身就很有趣。但是不同的行为,以及你必须知道你的回调是否使用this这一事实很重要,这意味着我们必须退回到直接编码,即使由于关键字function而显得冗长。

【讨论】:

  • 感谢您的解释 - 读者可能会找到以下链接,该链接描述了 Array.prototype.forEach() 的预期参数,以及传递给提供的回调的参数(如您所讨论的):developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 尽管您可以使用箭头函数:[1,2,3].forEach(v=>console.log(v))。 ;-)
  • 确实,我不敢相信我在 2014 年初还在使用长格式函数表达式作为 forEach(和朋友)的参数。不过,肯定在不久之后就切换了。跨度>
【解决方案2】:

实际上正如@SLaks 指出的那样,console.log 似乎在内部使用this,当它作为参数传递时this 现在指的是数组实例。

解决方法很简单:

var c = console.log.bind(console); [1,2,3,4,5].forEach(c);

【讨论】:

    【解决方案3】:

    这行得通:

    [1,2,3,4,5].forEach(console.log.bind(console));
    

    【讨论】:

    • 很好的答案,我想将其标记为已接受,但你能解释一下(对于那些不知道的人)你的代码是做什么的吗?如果不是,恐怕我将不得不接受我的,这会提供更多信息。谢谢
    • 不适用于 Node v6: > [1,2,3].forEach(console.log.bind(console)) 1 0 [ 1, 2, 3 ] 2 1 [ 1, 2 , 3 ] 3 2 [ 1, 2, 3 ]
    • 在 Node v7 中仍然失败。如果您只想记录数组的元素,我会避免使用此解决方案。此答案将console.log 应用于回调的三个参数,并打印出非常混乱且不需要的输出。尽管在编写答案时它可能确实起作用了,但这只是因为特定的 JavaScript 实现是错误的,恕我直言。这些天回调需要三个参数。
    【解决方案4】:

    我不能说我见过这种语法,但我的猜测是因为 log 需要一个参数,即登录控制台的消息/对象/等。

    在第一个示例中,您只是将函数引用传递给 forEach,如果您的函数不期望使函数按预期运行的参数,这很好。在第二个示例中,您传入 e 然后记录它。

    【讨论】:

    • 错误; forEach 正在传递一个参数。
    • 我试图说明的一点是,参数需要传递给 console.log,即 console.log(e)
    • 是的,这正是发生的事情。函数表达式中的函数和属性中的函数没有区别。
    猜你喜欢
    • 1970-01-01
    • 2021-05-29
    • 2015-09-09
    • 1970-01-01
    • 1970-01-01
    • 2022-10-12
    • 2018-06-14
    • 1970-01-01
    相关资源
    最近更新 更多