Thursday, February 17, 2011

Basic Javascript Call Types

Some of the hardest-to-understand things about Javascript are also some of the most basic concepts to any programming language. Take simple function declarations. Just input-output, parameters and an algorithm, right? Well, not quite. It's actually a bit more complicated.

Javascript is a dual-style language. You can program it procedurally, like C, or in an object-oriented manner, somewhat like Ruby or Perl. The basic function/class declaration takes the form:

function Name (parameter_list) { code_block }

The form above is really just syntactic sugar for function pointer assignment syntax:

var Name = function (parameter_list) { code_block }

Name is an alias for an anonymous function pointer. Furthermore, every object instance in Javascript is more or less equivalent to assignment of a simple anonymous hash table:

var Name = { code_block }

Above, we create an object called Name. There is no prototype (ancestral shadow object) attached to Name, as you would normally get if you used new() (which you can't with a hash), but member methods and properties assigned inline or posthumously will function just as if they were part of an object.

Similarly, a function declaration also doubles as a class declaration in Javascript:

// namespace collision wrapper START
(function () {

/* this is our dual class/function */

function Klass(param) 
   {
   this.inline_property = "I'm an inline_property.";
   this.inline_method   = function () 
      { 
      return "I'm an inline_method."; 
      }
   return "I'm a return value.";
   };

/*********************************/
/* add some members posthumously */
/*********************************/

/* Add static members to Klass */

Klass.static_property = "I'm a static_property."; 

Klass.static_method   = function ()
   { 
   return "I'm a static_method."; 
   } 

/* Add instance members to all objects created from Klass */

Klass.prototype.instance_property = "I'm an instance_property."; 

Klass.prototype.instance_method = function foo()
   { 
   return "I'm an instance_method."; 
   }

/**********************************************************/
/* Now let's see the different types of calls we can make */
/**********************************************************/

var d = document;

/* call as a plain old function */
d.write ("[Call as a function]<p>");

// prints "I'm a return value."
d.write ( Klass("parameter") + "<p>");

/* call as a static Class */
d.write ("[Call as a static class]<p>");

// prints "I'm a static_property."
d.write ( Klass.static_property + "<p>");

// prints "I'm a static_method."
d.write ( Klass.static_method() + "<p>");

/* call as an instance of Klass (an object) */
d.write ("[Call as an Object]<p>");

K = new Klass();

// prints "I'm an inline_property"
d.write ( K.inline_property + "<p>");

// prints "I'm an inline_method"
d.write ( K.inline_method() + "<p>");

// prints "I'm an instance_property"
d.write ( K.instance_property + "<p>");

// prints "I'm an instance_method"
d.write ( K.instance_method() + "<p>");

}) (); // namespace collision wrapper END

The point of the code above is to show that a function declaration can double as a class declaration. If the function Name (or Class Name) is new()-ed, it has nearly the full capability of an object. So not only is an object mostly interchangeable with a hash, but a class is mostly interchangeable with a function.

Class <=> Function and Object <=> Hash


How's that for confusing? Little old Javascript is not as simple as it seems!

No comments:

Post a Comment