views:

79

answers:

3

I'm sure this question has been answered before, but I don't think I'm using the right search phrase.

I think an example will explain better what I'm trying to ask:

var test = {};
test.example = function(parameter_2){
    alert(parameter_1+parameter_2);
}
test("parameter_1").example("parameter_2");

Obviously that last line won't work. Essentially wanting to do something like jQuery does with selectors, but just a little more archaic.

I'll probably just pass both parameters into the example(p1,p2) function.

It just sort of sparked my curiosity.

I found this: http://enterprisejquery.com/2010/08/javascript-parameter-patterns-with-extend-and-beyond/ but I don't think it quite answered my question.

+3  A: 

Edit this isn't a very good example, since this will pollute the global object. Use Rontologist's example.

Hmm try this

var test = function(parameter_1){

    this.example = function(parameter_2){
        alert(parameter_1+parameter_2);
    }

    return this;

};

test("parameter_1").example("parameter_2");
RueTheWhirled
Note that the `this` value will refer to the global object, because the way that `test` is being invoked, `example` will end up being a property of the global object (`window.example`).
CMS
heh, well, I had tried something similar, but I was using bg instead of this. Makes all the difference. @CMS - Thanks for the additional info.
Senica Gonzalez
Be very careful with the global scope of this. May lead to some weird issues and race conditions.
Rontologist
yeah thats true, I didn't really think it through
RueTheWhirled
Wrap it in a self calling anonymous function - `(function() { ... })();` to not attach `test` to `window` -------- **However**, not only are you attaching things to `window.test`, but also to `window.example`... take a look here ==> http://jsfiddle.net/7twuz/
Peter Ajtai
+1  A: 

A nonglobal way of doing what RueTheWhirled had said earlier:

function test(p1) {
  var obj = new Object();
  obj.example = function(p2) {
    alert(p1 + p2);
  }
  return obj;
}


test(1).example(2);

Its the same basic idea, but it changes a local object instead.

A comment was posted above asking for a link on this (which I don't have unfortunetly) but running the following snippet on this setup produces 4 and 6 as expected.

var a = test2(1);
var b = test2(2);

a.example(3);
b.example(4);
Rontologist
oh wow. that could lead to some issues. I guess I really didn't catch what CMS was saying about the property being attached to the window object.
Senica Gonzalez
Sorry, do you know of a link off the top of your head that explains why example does not stay inside the "test" namespace, but rather attaches to the global object instead? I clearly see that it does using firebug.
Senica Gonzalez
Not off the top of my head unfortunetly. I've been bitten by it before on some versions of IE. Not sure if Firefox has the same issues but I like being safe.
Rontologist
Just have to add --- darn you ie!!!!
Rontologist
:) I'll second that. I want to start a campaign called, "Recall IE"
Senica Gonzalez
@Senica - If you don't want `test` to be part of the global namespace, simply wrap it in a self calling anonymous functions ---- `(function() { /* test goes here */})();` . Additionally, you can create a slightly more elegant solution by making use of prototypal inheritance and the automatically created `arguments` array, so that you can have as much chaining with as many arguments as you want......... see my answer.
Peter Ajtai
+2  A: 

Method 1:

Why don't we create infinite chainability using prototypal inheritance, and create the possibility to pass in as many arguments as we want using the automatically created arguments array?

I'll present the simplified version. You can also create a pretty wrapper for all this, and return the wrapper to the world... the window, like on this page.

Take note, that you must use the new keyword with test... otherwise all of the this keywords will end up referring simply to the window.......... which isn't all that useful.


So, each instance of this object does 2 things:

  1. You can chain all the methods as much as you want. This is achieved by the use of return this;

  2. It keeps track of all the arguments passed in with this.args.


Example:

jsFiddle

new test("p1", "p2").example("p3").example("p4", "p5").showAll("p6", "p7", "p8");

// Output:
// The params are: p1, p2, p3, p4, p5, p6, p7, p8


The Code:

(function(){     // <== Let's not pollute the global namespace.        
    function test() {  // <== The constructor
          // Must copy arguments, since they're read only
        this.args = [];
        this.addArgs(arguments);
    }       
    // Add some methods:
    test.prototype = {
        example : function() {
                // Add on new arguments
            this.addArgs(arguments);
                // Return the instance for chainability            
            return this;
        },
        showAll : function() {
            var i, string = "The params are: ";
                // Add on new arguments
            this.addArgs(arguments);
                // show all arguments            
            alert(string + this.args.join(", "));
            return this;
        },
        addArgs: function(array) {
            var i;
            for (i = 0; i < array.length; ++i)
            { this.args.push(array[i]); }
            return this;
        }
    };       
new test("p1","p2").example("p3").example("p4","p5").showAll("p6","p7","p8");
})();​

Method 2:

This method is probably not quite as useful as the first when written like this, but makes better use of the classless nature of JS. It can be tweaked to be very useful in some situations. The trick is that in properties of an object, this refers to the object. In this case you don't have to use the new keyword, and you still get chainability, but the format becomes slightly different.... You essentially refer to Tdirectly.

Anyway, it's just an alternate method of creating chainability by using return this;:

(function(){     // <== Let's not pollute the global namespace.        
    var T = {}; // "this" will be T in the properties / methods of T
    T.args = [];
    T.example = function() {
       var i;
       for (i = 0; i < arguments.length; ++i)
       { this.args.push(arguments[i]); }    
       return this; // <== Chainability
    };
    T.show = function() {
        alert(this.args.join(","));   
        return this;
    }

    // Let's try it out:
    T.example("a", "b").example("c").show();
    // Output: a, b, c
})();​

jsFiddle example

Peter Ajtai
Nice. This looks a little more along the lines of what I was really looking for. At some point, got a days worth of work to go back through and tighten up now :)
Senica Gonzalez
This is one of those...give them a yard and they'll take a mile type question, so forgive the forwardness, I only have 478 characters left though :) I'm working on an open source project that I've had on the backburner for a while. Mind if I contact you in the future to see if you'd be interested in helping out? I'm not ready for any repository yet. I'm about two months out at 60 hours a week from being able to showcase a sneak peak...I think then I'll be looking for some volunteer help....anyways, I know this isn't the place so feel free to delete comment. [email protected]
Senica Gonzalez
@Senica - Stack Overflow takes up a lot of my "free" time, but you can find my contact info by looking on my profile and following the link there.
Peter Ajtai