George V
George V

Reputation: 59

Create a prototype method that works alone but can also have sub-methods

I don't know how else to name the title, sorry.

Here is an example, I want to be able to do this:

var str = 'bla bla bla';

str.do(a).thenDo(b) 

//but i also want to be able to do this:
str.do(a) // which will do something different

// I have tried this but it doesn't work:
String.prototype.do = function(a) {
  //here is some code to get the 'str' variable, then:
  var self = {};
  self.thenDo = function(b) {
    var someCalculations;
    return someCalculations + a + b;
  }
  self = function() {
    //this is supposed to be the do(a) function
    var moreCalculations;
    return moreCalculations + a;
  }
  return self;
}

NOTE: thenDo() needs to use the 'a' parameter from do() so something like this will not help in what i'm trying to achieve:

String.prototype.do = function(a) {
   var moreCalculations;
   return moreCalculations + a;
}
String.prototype.do.thenDo = function(b) {
   var someCalculations;
   return someCalculations + a + b;
}
//it doesnt work, thenDo() cant get the 'a' parameter

Furthermore I need this for a library that I'm developing so any jQuery answers will not help.

Thanks

Upvotes: 0

Views: 39

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074238

You've said:

str.do(a).thenDo(b) 

//but i also want to be able to do this:
str.do(a) // which will do something different

It's impossible for the do(a) part of that to do something different depending on whether its return value is used. E.g., the do(a) part of str.do(a) and str.do(a).thenDo(b) cannot know it's meant to do something different in those two cases. It just doesn't have that information (which is a Good Thing™).

You could make this work:

str.do(a)();           // Does one thing
str.do(a).thenDo(b);   // Does something else

Note the () at the end of the first one. That's the trigger that lets us differentiate the two cases:

(function() {
  function String$do(v1) {
    // This function is called if the caller uses () on the result
    function immediate() {
      console.log("something: ", v1);
    }
    // This is called if they use .thenDo() instead
    immediate.thenDo = function(v2) {
      console.log("something else: ", 1, v2);
    };
    return immediate;
  }
  Object.defineProperty(String.prototype, "do", {
    value: String$do
  });
})();

var str = "testing 1 2 3";
str.do(42)();
str.do(42).thenDo(67);


Side note: When extending built-in prototypes (which many advocate against), always be sure to use Object.defineProperty or Object.defineProperties and use the default for the enumerable flag (or explicitly set it to false) so you don't create an enumerable property. That won't help with naming conflicts, but it may help with code naively assuming only the default set of built-in prototype properties in for-in loops, in checks, etc.

Upvotes: 2

Related Questions