console.log() called on object other than console

2019-03-22 13:42发布

问题:

I remember that always when I wanted to pass console.log as a callback parameter to some function, it didn't work unless I used the bind() method to bind console to it.

For example:

const callWithTest = callback => callback('test');
callWithTest(console.log); // That didn't use to work.
callWithTest(console.log.bind(console)); // That worked (and works) fine.

See Uncaught TypeError: Illegal invocation in javascript.

However, recently I noticed that console.log() works fine even when called on object other than console. For example:

console.log.call(null, 'test');

logs 'test'.

When and why did it change? Does the specification say anything about it?

回答1:

Editor's Draft of Console API used to say:

Logging APIs SHOULD all be callable functions allowing them to be passed as arguments to error handling callbacks, forEach methods, etc.

This is no longer included in the current version of the specification.

I thought that Chrome and Node.js changed it to work like in the specification, but it seems that it worked like that even before it.

I'm still curious when did it change and what was the reason of that.



回答2:

I don't know when the change was made, but I have an idea about why it didn't work.

Consider the following code

callWithTest = callback => callback('test');
var Demo = function () {this.str = 'demo';}
Demo.prototype.getStr = function () { return this.str;}
demo = new Demo ();
demo.getStr(); // returns 'demo'
callWithTest(demo.getStr); // returns undefined
window.str = 'window';
callWithTest(demo.getStr); // returns 'window'

If you trace the code, you will see that when demo.getStr gets called through another function, this refers to window, and sine str is not defined within window, it returns undefined. If you called it directly or bind with demo, this refers to demo and thus it returns 'demo'.

In nodeJS (v6.6.0), there exists a class called Console within the console module which user can explicitly pipe logs into a file (or whatever stream a user like). According to Node.js v6.6.0 api specification,

console = new Console(process.stdout, process.stderr);

Console does not exist in browser as it isn't necessary. The output of console only exists in a canvas used for debugging, and there are exactly one instance of it. User can't, and should not be able to, pipe output of console to any other places as it will become a serious security issue. Because of this, developers can do something within the log function like var x = this.x || console.x as there is exactly one instance of the console object.