为什么当作为参数传递给 forEach 时,console.log 不起作用?

IT技术 javascript arrays function foreach
2021-03-13 00:16:55

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

[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) });

所以... ?

4个回答

值得指出的是,在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 ]

但还有一种替代方法:请注意,第二个参数 toforEach取值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 控制台和节点。当然,我确定您想要的只是value观,所以恐怕最好的解决方案确实是:

> [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/参考/...
2021-04-16 00:16:55
尽管可以使用箭头函数:[1,2,3].forEach(v=>console.log(v)). ;-)
2021-04-18 00:16:55
事实上,我不敢相信我还在forEach2014 年初使用长形式的函数表达式作为(和朋友)的参数。不过不久之后肯定已经切换了。
2021-04-26 00:16:55

这有效:

[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 ]
2021-04-21 00:16:55
在 Node v7 中仍然失败。如果您只想记录数组的元素,我会避免使用此解决方案。这个答案适用console.log于回调的三个参数,并打印出非常混乱和不需要的输出。不过,在编写答案时它可能确实有效,但这只是因为特定的 JavaScript 实现是错误的,恕我直言。现在回调需要三个参数。
2021-04-22 00:16:55
很好的答案,我想将其标记为已接受,但您能解释一下(对于那些不知道的人)您的代码是做什么的吗?如果不是,恐怕我将不得不接受我的,这会提供更多信息。谢谢
2021-05-02 00:16:55

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

解决方法很简单:

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

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

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

错误的; forEach正在传递一个参数。
2021-04-22 00:16:55
是的,这正是发生的事情。函数表达式中的函数和属性中的函数之间没有区别。
2021-04-26 00:16:55
我试图提出的观点是参数需要传递给console.log,即console.log( e )
2021-05-12 00:16:55