Why doesn't JavaScript function aliasing work?
Yes, you should persist the context :
var log;if (window.console && typeof console.log === "function"){ // use apply to preserve context and invocations with multiple arguments log = function () { console.log.apply(console, arguments); };} else { log = function(){ return; }}
What is happening is that the context (the this
value), is implicitly set when you call a function, for example:
var obj = { method: function () { return this; }};obj.method() === obj; // true
In this case, you are calling a function that is defined as a property of an object, when the function is invoked, the this
value is set to that object.
Now as in your example, if you copy a reference of that method to a variable:
var method = obj.method;method() === window; // global object
As you can see, the this
value refers to the global object.
So, to avoid this implicit behavior you can set the context explicitly, with the call
or apply
functions.
The problem with wrapping a function (like console.log) in a function is that it loses its context, i.e. it will not show the correct line number of the file that we've put our "log" shortcut in.
Instead I suggest something like this:
window.log = ((window.console && window.console.log) ? console.log.bind(console) : function(){});
This works with firebug & chrome dev tools and does not throw errors when no console is available. And - most importantly - shows the correct file & line number.
This doesn't work:
log("hi");
While this does:
log.call(console, "hi");
It is obvious that you need to call the aliased function with the correct context -- as you yourself have mentioned.
I think you'll have to use a function wrapper (a closure that has a reference to the original context) rather than an alias...
Update
Also note that if you check for console
directly, you may get a run-time error when the variable doesn't exist. You're better off checking it explicitly as window.console
. Here's one way to implement a conditional log
wrapper:
var log = (function (console) { return console ? function () { console.log.apply(console, arguments); } : function () {}})(window.console);