Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A (somewhat obscure) Javascript inheritance question

I have been experimenting with a design pattern in Javascript that would allow me to have what appears to be singleton functions that can be overridden by instance functions.

Here's a brief example:

Date.tomorrow = function () {
  return Date.today().add(1).days();
}

(function(p) {

  p.tomorrow = function() {
    var date = this.clone().clearTime();
    return date.equals(Date.tomorrow());
  }

})(Date.prototype);

So there are two tomorrow() functions. When called from the Date function directly:

>>> Date.tomorrow()
=>  Fri Jul 23 2010 00:00:00 GMT-0500 (CST) { _orient=1,  more...}

But when you instantiate a Date instance first:

>>> var date = new Date()
>>> date.tomorrow()
=>  false

I'm leaving a lot out as I'm sure you can tell, but hopefully you get the point. My question is this: what is the relation of the first tomorrow() function to the Date object? What is it attached to, exactly?

Let's say you were doing this with a normal function that was not intended to be a constructor. Is it possible to call the augmented function from within the original function?

In a constructor function you could do this:

this.constructor.functionName();

but if the function isn't being used as a constructor, obviously the constructor reference wouldn't exist. Is there another way to access that augmented function?

The impetus behind this question comes from my work reorganizing the JS code for a project. We're implementing the Sprockets system to split our source code into modules, in which were are basically decorating a base namespace as we go instead of packing it all together in one unreadable inline object definition.

We have some pretty epically large event wireup, which is nice to split up into separate functions, but I'd rather not have to call each function individually; instead I'd like a superfunction that calls all of the sub-functions in one go.

I could always create an all() function or something to achieve this, but it would look a lot cleaner from an API standpoint if calling a top-level function executed all of the sub-functions that had been attached to it.


Thanks to Francisco's response I now have a working implementation of what I was thinking about. Here's an example in case anyone was curious.

var Namespace = {};

var Namespace.wireup = (function () {

  return function () {
    var self = arguments.callee;
    self.eventWireup1();
    self.eventWireup2();
  };

})();

(function (W) {

  function eventWireup1 () { console.log('first function'); };
  function eventWireup2 () { console.log('second function'); };

  $.extend(W, {
    eventWireup1: eventWireup1,
    eventWireup2: eventWireup2
  });

})(Namespace.wireup);

The benefit of this API is that you can do this:

>>> Namespace.wireup.eventWireup1();
=>  first function
>>> Namespace.wireup.eventWireup2();
=>  second function
>>> Namespace.wireup();
=>  first function
=>  second function
like image 680
Adam Lassek Avatar asked Nov 06 '22 10:11

Adam Lassek


1 Answers

Date is a function() of the window object, and you are attaching another function to the function. Weird uh?

Try this:

function a()
{
    return 10;
}

a.e = "oO";

typeof(a);
typeof(a.e);

To access e from inside a you can use the callee property from arguments, like:

function a () {
    return arguments.callee.e;
}

a.e = "Oo"

a();
like image 145
Francisco Soto Avatar answered Nov 11 '22 08:11

Francisco Soto