How do object or method chaining work in jQuery?
If you have an object with certain methods, if each method returns an object with methods, you can simply call a method from the object returned.
var obj = { // every method returns obj---------v
first: function() { alert('first'); return obj; },
second: function() { alert('second'); return obj; },
third: function() { alert('third'); return obj; }
}
obj.first().second().third();
DEMO: http://jsfiddle.net/5kkCh/
How can jQuery do method chaining?
//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:
this
inside of thefoo
refers to a freshly made copy offoo.prototype
foo.prototype
is returned (unlessfoo
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.
How does jQuery chain functions while still returning an array?
Using the jQuery source code viewer site the definition for $ (http://james.padolsey.com/jquery/#v=1.9.1&fn=$) is as follows:
$
function (selector, context) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init(selector, context, rootjQuery);
}
Notice it is returning from init(). Inside of init (http://james.padolsey.com/jquery/#v=1.9.1&fn=init) we see that at the end it calls a function called makeArray:
init
function (selector, context, rootjQuery) {
var match, elem;
// rest of function defintion
return jQuery.makeArray(selector, this);
}
Which brings us to the answer to the question 'How does jQuery chain functions while still returning an array?'
makeArray (http://james.padolsey.com/jquery/#v=1.9.1&fn=jQuery.makeArray) looks like this:
makeArray
function (arr, results) {
var ret = results || [];
if (arr != null) {
if (isArraylike(Object(arr))) {
jQuery.merge(ret, typeof arr === "string" ? [arr] : arr);
} else {
core_push.call(ret, arr);
}
}
return ret;
}
jQuery - Chaining custom functions
You need to return current element context, i.e. this
from you custom method.
$.fn.foo = function() { var html = '<div class="foo"></div>'; if ($(this).hasClass('somthing')) { $(this).prepend(html); } return this; //The magic statement}
$.fn.bar = function() { var html = '<h3>bar</h3>'; $(this).find('.foo').prepend(html); return this; //The magic statement}
$('body').addClass('somthing').foo().bar();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
How this code works? (jQuery chaining)
This is due to the nature of append(function)
and the difference in scope between the initial this
and the one inside the function in your code.
Per the jQuery documentation at http://api.jquery.com/append/#append-function, append(function)
operates on "each element in the set of matched elements. [...] Within the function, this
refers to the current element in the set."
So, in your code, this.filter("a")
is a jQuery object containing any matching elements, while this.href
within the function itself represents each of those elements in turn during the iteration through the collection. Hence, the text is appended to all of the matching elements.
jQuery chaining order
Chaining itself doesn't guarantee order of execution, it only returns the previous jQuery context so that you'll be able to further work with it in a fluent way.
In your specific case, the invocation of slideUp
and slideDown
functions takes time to complete (because of their animated nature), but jQuery will not wait for them to finish before calling further (chained) methods.
You need to pass a callback instead:
$("#p1")
.css("color", "red")
.slideUp(2000, function() {
$(this).slideDown(2000, function() {
$(this).css("color", "blue");
});
});
See Fiddle
Javascript JQuery chaining
So I was wondering how can JQuery return both the nodelist and itself to allow chaining ?
It doesn't.
It only returns itself (which it an object).
That object has a property called 0
which contains the first element in the array of elements. It also has a property called html
which contains a function.
How does basic object/function chaining work in javascript?
In JavaScript Functions are first class Objects. When you define a function, it is the constructor for that function object. In other words:
var gmap = function() {
this.add = function() {
alert('add');
return this;
}
this.del = function() {
alert('delete');
return this;
}
if (this instanceof gmap) {
return this.gmap;
} else {
return new gmap();
}
}
var test = new gmap();
test.add().del();
By assigning the
new gmap();to the variable test you have now constructed a new object that "inherits" all the properties and methods from the gmap() constructor (class). If you run the snippet above you will see an alert for "add" and "delete".
In your examples above, the "this" refers to the window object, unless you wrap the functions in another function or object.
Chaining is difficult for me to understand at first, at least it was for me, but once I understood it, I realized how powerful of a tool it can be.
Why does chaining on multiple lines work in jquery?
delay()
, fadeIn()
, and fadeOut()
all work by applying operations to the internal animation queue that jQuery maintains. As such, each call adds operations to the queue, and they (the queued operations) execute in the order they are added on the queue.
http://api.jquery.com/delay/ makes reference to this queue as the second argument, which if not provided defaults to the fx
queue.
Related Topics
How to Update State.Item[1] in State Using Setstate
How to Get Current Value of Rxjs Subject or Observable
How to Turn JavaScript Array into Comma-Separated List
Getelementsbyclassname() Doesn't Work in Old Internet Explorers Like IE6, IE7, IE8
JavaScript Date Regex Dd/Mm/Yyyy
Get the Data of Uploaded File in JavaScript
Prevent Form Submission with Enter Key
Detecting That the Browser Has No Mouse and Is Touch-Only
Is It Safe to Store a Jwt in Localstorage with Reactjs
Jquery Checkbox Change and Click Event
What Does the Plus Sign Do in '+New Date'
How to Fix Navigator/Window/Document Is Undefined in Nuxt
Es6 Modules: Undefined Onclick Function After Import
Get Unique Selector of Element in Jquery