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

Pab*_*dez 25 javascript arrays foreach function

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

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

// Prints 'Uncaught TypeError: Illegal invocation' in Chrome
Run Code Online (Sandbox Code Playgroud)

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

[1, 2, 3, 4, 5].forEach(function(n) { console.log(n) });
Run Code Online (Sandbox Code Playgroud)

那么......?

Ray*_*oal 25

值得指出的是,实施中的行为存在差异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 ]
Run Code Online (Sandbox Code Playgroud)

这是因为回调forEach是一个三参数函数,它取值,索引和数组本身.该函数console.log可以看到这三个参数并尽职地记录它们.

但是,在Chrome浏览器控制台下,您可以获得

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

在这种情况下,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 ]
Run Code Online (Sandbox Code Playgroud)

但是有另一种方法:注意第二个参数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 ]
Run Code Online (Sandbox Code Playgroud)

适用于我的Chrome控制台和节点.当然,我确定你想要的只是价值观,所以我担心最好的解决方案是:

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

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


Tom*_*icz 11

这有效:

[1,2,3,4,5].forEach(console.log.bind(console));
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案,我想将其标记为已被接受,但您能解释(对于那些不知道的人)您的代码的作用吗?如果不是,我恐怕我不得不接受我的更多信息.谢谢 (3认同)
  • 在节点v6中不起作用:> [1,2,3] .forEach(console.log.bind(console))1 0 [1,2,3] 2 1 [1,2,3] 3 2 [1, 2,3] (2认同)

Pab*_*dez 9

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

解决方法很简单:

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