Why doesn't console.log work when passed as a

2019-01-05 02:45发布

This is just out of curiosity, but do any of you have an idea why this code won't work?

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

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

On the other hand, this seems to work fine:

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

So... ?

4条回答
Melony?
2楼-- · 2019-01-05 03:30

It's worth pointing out that there is a difference in behavior in the implementation of console.log. Under node v0.10.19 you do not get an error; you simply see this:

> [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 ]

This is because the callback to forEach is a three-parameter function taking the value, the index, and the array itself. The function console.log sees those three parameters and dutifully logs them.

Under the Chrome browser console, however, you get

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

and in this case, bind will work:

 > [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 ]

but there is an alternative way: note that the second parameter to forEach takes the value of this to use in the callback:

> [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 ]

which works in the Chrome console and node for me. Of course, I'm sure what you want is just the values, so I'm afraid the best solution is, indeed:

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

Whether node's behavior is a bug, or it simply takes advantage of the fact that console.log is not specified by ECMA is interesting in its own right. But the varying behavior, and the fact that you have to be aware of whether your callback uses this is important and means we have to fall back to direct coding, even if it is verbose thanks to the keyword function.

查看更多
女痞
3楼-- · 2019-01-05 03:32

I can't say I've seen that syntax, but my guess is because log expects a parameter, being the message/object/etc to log in the console.

in the first example, you are just passing a function reference to forEach, which is fine if your function doesn't expect paramater which make the function behave as expected. In the second example you pass in e and then log it.

查看更多
劫难
4楼-- · 2019-01-05 03:34

This works:

[1,2,3,4,5].forEach(console.log.bind(console));
查看更多
啃猪蹄的小仙女
5楼-- · 2019-01-05 03:49

Actually as @SLaks pointed out, console.log seems to be using this internally and when it's passed as a parameter this now refers to the array instance.

The workaround for that is simply:

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

查看更多
登录 后发表回答