Reputation: 44091
In the code below I can use print in place of console.log and the program can run correctly. However I wish to use console.log but I get
Illegal invocation
at runtime
function forEach(array, action) {
for (var i=0; i<array.length; i++)
action(array[i]);
}
forEach(["blah", "bac"], console.log);
Upvotes: 7
Views: 4502
Reputation: 69964
In general you can't pass methods directly to callbacks in Javascript. The this
is bound at the point of the function call, depending on what form you call it and there is no automatic binding of methods (like there is in, for example, Python)
//does not work.
var obj = {
x: 17,
f: function(){ return this.x; }
};
//inside doSomething, f forgets its "this" should be obj
doSomething( obj.f )
In these cases, one might use Function.prototype.bind
(or a similar function from your library of choice, since bind
is not present in IE <= 8)
//works (for normal methods - see next bit for console.log in particular)
var obj = {
x: 17,
f: function(){ return this.x; }
};
doSomething( obj.f.bind(obj) )
Unfortunately, however, this is not always enough for console.log. Since it is not an actual Function in IE, (its an evil host object) you cannot use bind, apply and call methods on it on that browser so the only workaround is falling back to wrapping the call in an anonymous function
doSomething( function(x){
return console.log(x);
});
Since wrapping console.log in an anonymous function is long and annoying to type I usually add the following global function when I'm developing and debugging:
function log(message){ return function(x){
return console.log(message, x);
};};
forEach(['asd', 'zxc'], log('->'));
Upvotes: 7
Reputation: 5739
From here : Create shortcut to console.log() in Chrome
You can replace console.log
with console.log.bind(console)
Explanation thanks to @julian-d :
Because the
console.log
will refer internally tothis
and expects it to beconsole
. If you 'detach' thelog
method e.g. likevar log = console.log
, this association is lost and this will no longer point toconsole
(in this case towindow
instead - if you are in a browser). This is the purpose of.bind(obj)
: it returns a method where internallythis
stays fixed toobj
.
Upvotes: 4
Reputation: 3496
You can solve the problem using an anonymous function acting as a bridge between forEach()
and console.log()
forEach(["blah", "bac"], function (element) {
console.log(element);
});
Your forEach()
remains agnostic about the handler and you don't have to juggle with bind()
to pass a working reference to console.log()
.
Upvotes: 3