Tuesday, June 1, 2010

JavaScript: functions as objects vs. functions as functions


I ran into this interesting behavior today. I was passing a function to a list of functions to execute later, and I kept getting an error in firebug that said when it came to execute it that it "is not a function", but proceeded to completely successfully execute it as one anyway, doing exactly what I wanted it to. I wanted to get rid of the error message, since it was behaving properly.


Come to find out, it was listed as an object instead of a function. In short, the difference is that if you declare a function like this: function() { ... }, it will be returned as a function. If you declare it like this: new function() { ... }, it will be returned as an object. I just needed to take out the word "new" I had used.


I created the following simple HTML page to demonstrate this behavior. Feel free to try it out for yourself and tinker around with it:

<html>
<head>
<script type="text/javascript">
//setup
var tests = new Array();
tests[0] = new function() { return 'A is the best!'; };
tests[1] = function() { return 'B is better!'; };

var message = 'tests:';
for (var i = 0; i < tests.length; i++)
{
message += '\ntest[' + i + ']: ' + tests[i];
}
alert(message +'\n\nNext, we\'ll try to execute these as functions...');
</script>
</head>
<body>
<div id="divResults"></div>
<br />
<div id="divStatus">Testing...</div>
</body>
<script type="text/javascript">
//run the tests
var resultsDiv = document.getElementById('divResults');
for (var i = 0; i < tests.length; i++)
{
resultsDiv.innerHTML += 'test[' + i + ']\'s result: ';
try { resultsDiv.innerHTML += tests[i](); }
catch(ex) {resultsDiv.innerHTML += '<span style="color:red;">Test failed: ' + ex.message + '</span>'; }
resultsDiv.innerHTML += '<br />';
}

//we're done
document.getElementById('divStatus').innerHTML = 'The test is done. Reload this page to run the test again.';
</script>
</html>


I have confirmed this behavior in Firefox 3.6.3, IE 7.0, Chrome 5.0, Safari 4.0.5, and Opera 10.53.