1

Possible Duplicate:
how does jquery chaining work?

This is a normal thing you would see in a jQuery code:

$("div.selected").html("Blah.");

So, in the above code, in the function $(), it has a function called html(). And what I don't understand is, what I normally will do is:

funcA("blah");  //normal function, cool.
funcA.funcB("blah");  //normal function in an object, still cool.

and now this is confusing:

funcA("blah").funcB("blah")  //huh??

How can funcB knows the arguments in funcA?
How can jQuery achieve this?

Thanks.

Community
  • 1
  • 1
Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • [how does jquery chaining work?](http://stackoverflow.com/questions/7475336/how-does-jquery-chaining-work) –  Jan 04 '12 at 03:23
  • If the return value of `funcA("blah")` is an object, then it can have a property `funcB` which can be a function... – Šime Vidas Jan 05 '12 at 00:36

7 Answers7

2

When you do funcA("blah").funcB("blah"), then funcB is called on whatever funcA returns. So you have funcA return some object that has a funcB, which is then called.

In the case of jQuery, most jQuery functions return the jQuery object, so function calls can be chained as much as you like. Many jQuery functions are designed to modify the contents of the jQuery object that is returned. So in your example, it's not the case that the call to html() "knows about" what was passed to the $() function. Rather, the $() function returns a jQuery object that points to the DOM elements that match the given selector. Further calls to functions on that jQuery object, then, will affect those selected elements.

Jacob Mattison
  • 50,258
  • 9
  • 107
  • 126
2
//function returning an object is a possibility. bar has access to elem because of
// the shared scope
function foo ( elem ) {
    return {
        bar : function () {
            return elem.id;
        }
    };
}

In this one, the foo function returns an object containing whatever methods you wish. So when you call foo, you receive this:

{
    bar : function () {
        return elem.id;
    }
}

elem is present from your call to foo. If you were to add a console.log( elem ) at the top of bar, you'd see that it's the same thing as what you passed to foo.

//this is kinda how jQuery does it:
var foo = (function() {
    function foo ( elem ) {
        this.elem = elem;
    }

    foo.prototype.bar = function () {
        return this.elem.id;
    };

    return function ( elem ) {
        return new foo( elem );
    };
}());

This is a little more complex, and actually divided into two.

function foo ( elem ) {
    this.elem = elem;
}

foo.prototype.bar = function () {
    return this.elem.id;
};

Who doesn't love prototypical inheritance mixed with classical inheritance names? Anyway...functions act as both regular functions and as constructors. Meaning, when called with the new keyword, two special things happen:

  1. this inside of the foo refers to a freshly made copy of foo.prototype
  2. foo.prototype is returned (unless foo returns an object)

Note that foo.prototype isn't a magic value. It's just like any other object property.

So, inside the foo function/constructor, we're merely setting foo.prototype.elem, but not directly. Think of it like this (a little inaccurate, but it'll do): foo.prototype is the blueprint of a product. Whenever you wish to make more, you use the blueprint - duplicate what's inside, pass it along. Inside of foo, this refers to such a replication of the blueprint.

However, by explicitly setting values on foo.prototype, we're altering the blueprint itself. Whenever foo is called, it'll be called with this altered blueprint.

Finally, once foo is finished, the replication (the duplicated blueprint, but after foo has done stuff with it) is returned. This replication contains the original blueprint, and everything else we might have added - in this example, elem.

var foo = (function() {
    ...
    return function ( elem ) {
        return new foo( elem );
    };
}());

We create a nameless function and immediately execute it.

(function () {
    console.log( 'meep' );
}());

//is the equivalent of:
var something = function () {
    console.log( 'meep' );
};
something();
something = undefined; //we can no longer use it

//and of this
function () {
    console.log( 'meep' );
}(); //<--notice the parens
//however, it's considered good practice to wrap these self-executing-anonymous-functions
// in parens

Like all other functions, they can return values. And these values can be captured into variables.

var answer = (function () {
    return 42;
}());
answer ==== 42;

var counter = (function () {
    var c = 0;
    return function () {
        return c++;
    };
}());
//counter is now a function, as a function was returned
counter(); //0
counter(); //1
counter(); //2...

So:

var foo = (function () {
    ...
    return function ( elem ) {
        ...
    };
}());

Returns a function which receives an argument, and that function is now assigned to foo.

The insides of the function:

return new foo( elem );

Is to ensure the special conditions I've spoken about above - it ensures that a new copy of the blueprint is manufactured, by explicitly doing the new operation. This can actually be replicated like this:

function foo ( elem ) {
    this.elem = elem;
}
foo.prototype.bar = function () {...};

As long as you always call foo with the new keyword.

Zirak
  • 38,920
  • 13
  • 81
  • 92
0

Most functions in jquery return a jquery object which contains a set of elements. html doesn't know the arguments of $() exactly, it's more that the result of $() has a set of elements which are created based on the parameter passed to $().

In your example of funcA and funcB though, you could easily have funcA return an object which has a function named funcB. This object could also contain the value passed to funcA and then a call to funcB could "know" that value as well.

http://jsfiddle.net/ScENm/

James Montagne
  • 77,516
  • 14
  • 110
  • 130
0
function funcA(arg1) {

    var enclosedVariable= arg1;

    return {
       funcB: function () {
          alert(enclosedVariable);
       }
    };
}

Here is a quick and dirty example. ^^

funcA takes an argument and saves it then returns an object containing a single function. It has been "enclosed" and now funcB has access to this.

Technically you don't even have to save it... arg1 is available to funcB as well.

John Strickler
  • 25,151
  • 4
  • 52
  • 68
0

You should research chaining, it's what you're describing. You can google "jQuery chaining" to get started. Also check out jQuery's pluging tutorial for some more info

qwertymk
  • 34,200
  • 28
  • 121
  • 184
0

A function isn't anything special, you can return a function inside an object. For a quick example:

function $() {
    return {
        html: function() {
        }
    };
}

$().html(); // You just called the function!

jQuery doesn't have anything special in it. When you call a function in jQuery that doesn't return a value, it usually returns the jQuery object it was called on, like so:

var obj = {
    doSomething: function() {
        return this;
    },
    doSomethingElse: function() {
        alert('Hi!');
    }
};

obj.doSomething().doSomethingElse(); // Alerts "Hi!"

because again, it's just an object.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • So, how can `html()` knows what is passed to `$()`? – Derek 朕會功夫 Jan 04 '12 at 03:38
  • 1
    @Derek: The selector is stored inside the object. [Kind of like this.](http://jsfiddle.net/minitech/TAxVA/) – Ry- Jan 04 '12 at 03:44
  • 1
    @Derek: I modified my answer to respond to this; briefly, `html()` doesn't know what was passed to `$()`, but the call to `$()` resulted in a jQuery object that contains the appropriate DOM elements (as filtered by the selector that was passed in). The `html()` call, then, acts on that jQuery object and so affects those particular elements. – Jacob Mattison Jan 04 '12 at 03:47
  • @JacobM: Maybe you should notify Derek, not me :) – Ry- Jan 04 '12 at 03:48
0

Chaining is generally done on the basis of the object that a method should return. If object A be an instance of class A and a method in it returns object A then the returned object can again be applied to the same class and this can be arranged in a chaining fashion. Or say object of class A returns object of class B then, the returned object can be applied to the method of class B.

objectOfA->methodOfA(arg)->methodOfB(args);

In this case if objectOfA->methodOfA(arg) returns object of class B and hence the method of class B can be called upon it and chained as above.

In your case,

$('div.selected').html('Blah ..')

Here $('div.selected') return a jquery element object(or array of object); upon which the method .html() can be applied since the method is only applicable to element object of jquery. It is just chaining as other programming languages do.

In case of PHP this case looks like,

$class->method1(argument)->method(2) 

In this case, if class A has two methods method1 and method2 and method1 return the instance of its own then method 2 is again applicable to it.

This can be related to a function as well. Lets us suppose I have a function as such;

def function1(name):
    return name

def function2(arg):
    print len(name)

Now, this two functions can be chained simply as,

function2(function1('My Name is blah ...'))

Since the function1 returns a value, the type of the value must match to the input argument of function2 and this is how object work.

Sandeep
  • 20,908
  • 7
  • 66
  • 106