This question already has answers here:
Closed 11 years ago.
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.
//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 the foo refers to a freshly made copy of foo.prototype
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.
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.
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/
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.
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
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.
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.
Related
[This is related to Bound function instead of closure to inject extra arguments, but that was neither clearly asked nor answered.]
I'm calling a function that expects a function as its argument. I want to pass a method from my class, bound to an instance of my class. To make it clear, assume my class looks like:
var MyClass = function() {}
MyClass.prototype.myMethod = function() { ... }
var my_instance = new MyClass();
Is there any substantive difference between using bind:
doSomething(my_instance.myMethod.bind(my_instance))
and wrapping the call in an anonymous function:
doSomething(function() { my_instance.myMethod(); })
?
If a prototype within your class needs to generate a callback, it may not know its instance's name. As a result, you'll need to use this, but the value of this depends on where the callback was executed.
Consider the following example:
var MyClass = function (x) { this.something = x; };
MyClass.prototype.makeCall = function () {
var myBadCallback = function() { console.log(this.something); };
var myGoodCallback = function() { console.log(this.something); }.bind(this);
// When called, the value of "this" points to... we don't know
callMeBack( myBadCallback );
// When called, the value of "this" points to this instance
callMeBack( myGoodCallback );
};
function callMeBack( callback ) { callback(); };
var foo = new MyClass('Hello World!');
var bar = new MyClass('Goodbye!');
// Probably prints "undefined", then prints "Hello World!"
foo.makeCall();
// Probably prints "undefined", then prints "Goodbye!"
bar.makeCall();
In the above example, the first output probably prints undefined because the context (what this refers to) has changed by the time the callback has executed.
This example may seem contrived, but these sort of situations do arise, a common case being AJAX callbacks.
I'm, curios how the _.chaining function is implemented and how (or better, why) it works the way it does.
Especially my question is where does the wrapping for each function happen. Let's assume I'm using _.chain(someArray).filter(...); When I step into the function, I can see that the filter function got transformed into something like
function () {
var args = [this._wrapped]; //the data from chain(...)
push.apply(args, arguments); //push to the (?) array
return result.call(this, func.apply(_, args)); //?? where are these coming from?
}
I can see that the function has 3 Closures in it's scope (compare this to the un-chained function that show the definition of the function without all the Closure to it's original function)
The first one is the find function itself, the second "the safe reference to the object itself" and the third on the underscore class itself.
When calling _.chain(), how and where (code-wise) does the transformation (the creating of the scopes etc). I can see that
//http://underscorejs.org/docs/underscore.html#section-139
_.chain = function(obj) {
return _(obj).chain();
};
gets called and this goes to
//http://underscorejs.org/docs/underscore.html#section-145
//...
chain: function() {
this._chain = true;
return this;
},
//...
Then I'm stuck. I can't figure out what happens from there. I assume that the magic happens inside the constructor, but I can't seem to figure out where the additional creation of the Closures comes in. All the functions themselves don't show any sign of being wrapped, the chain call doesn't look like it wraps something. result seems to be there but I don't know where it came from. So, where and how does this happen?
_.chain(obj) returns new instance of _ with attribute _chain = true, that instance of _ has a _wrapped attribute set to current object (great work here). _.mixin(_) in line #1210 add all of underscore methods to underscore (constructor). _.mixin method replace and extend _ methods (still has the parent functions! Accessible via _.prototype). _.mixin change functions of that _ instance (this is the place you see that new function).
New function is:
function () {
var args = [this._wrapped];
push.apply(args, arguments);
return result.call(this, func.apply(_, args));
}
(doesn't matter what method it is, same for all, func is referenced to the original method)
result method function is :
var result = function(obj) {
return this._chain ? _(obj).chain() : obj;
};
so if the object returned by func.apply(_, args) has _chain (_.chain set that attribute) returns _(obj).chain() then you can use it again :)
This is process of chaining but what about prototypes!
In constructor function :
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj); // This line do the magic
this._wrapped = obj;
};
Consider this :
func = function(a){this.a = a;}
b = func(2);
b.a // TypeError: Cannot read property 'a' of undefined
c = new func(2);
c.a // returns 2, whooa this the magical javascript!
Read this (Underscore docs about OOP) if you want to learn more about underscore mixin function
Am I missing something?
Here's a sample of a simple Javascript class with a public and private method (fiddle: http://jsfiddle.net/gY4mh/).
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction();
}
}
ex = new Example;
ex.publicFunction();
Calling the private function from the public one results in "this" being the window object. How should I ensure my private methods are called with the class context and not window? Would this be undesirable?
Using closure. Basically any variable declared in function, remains available to functions inside that function :
var Example = (function() {
function Example() {
var self = this; // variable in function Example
function privateFunction() {
// The variable self is available to this function even after Example returns.
console.log(self);
}
self.publicFunction = function() {
privateFunction();
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Another approach is to use "apply" to explicitly set what the methods "this" should be bound to.
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.apply(foo, null);
// => foo
Yet another approach is to use "call":
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.call(foo, null);
// => foo
both "apply" and "call" take the object that you want to bind "this" to as the first argument and an array of arguments to pass in to the method you are calling as the second arg.
It is worth understanding how the value of this in javascript is determined in addition to just having someone tell you a code fix. In javascript, this is determined the following ways:
If you call a function via an object property as in object.method(), then this will be set to the object inside the method.
If you call a function directly without any object reference such as function(), then this will be set to either the global object (window in a browser) or in strict mode, it will be set to undefined.
If you create a new object with the new operator, then the constructor function for that object will be called with the value of this set to the newly created object instance. You can think of this as the same as item 1 above, the object is created and then the constructor method on it is called.
If you call a function with .call() or .apply() as in function.call(xxx), then you can determine exactly what this is set to by what argument you pass to .call() or .apply(). You can read more about .call() here and .apply() here on MDN.
If you use function.bind(xxx) this creates a small stub function that makes sure your function is called with the desired value of this. Internally, this likely just uses .apply(), but it's a shortcut for when you want a single callback function that will have the right value of this when it's called (when you aren't the direct caller of the function).
In a callback function, the caller of the callback function is responsible for determining the desired value of this. For example, in an event handler callback function, the browser generally sets this to be the DOM object that is handling the event.
There's a nice summary of these various methods here on MDN.
So, in your case, you are making a normal function call when you call privateFunction(). So, as expected the value of this is set as in option 2 above.
If you want to explictly set it to the current value of this in your method, then you can do so like this:
var Example = (function() {
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction.call(this);
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Other methods such as using a closure and defined var that = this are best used for the case of callback functions when you are not the caller of the function and thus can't use 1-4. There is no reason to do it that way in your particular case. I would say that using .call() is a better practice. Then, your function can actually use this and can behave like a private method which appears to be the behavior you seek.
I guess most used way to get this done is by simply caching (storing) the value of this in a local context variable
function Example() {
var that = this;
// ...
function privateFunction() {
console.log(that);
}
this.publicFunction = function() {
privateFunction();
}
}
a more convenient way is to invoke Function.prototype.bind to bind a context to a function (forever). However, the only restriction here is that this requires a ES5-ready browser and bound functions are slightly slower.
var privateFunction = function() {
console.log(this);
}.bind(this);
I would say the proper way is to use prototyping since it was after all how Javascript was designed. So:
var Example = function(){
this.prop = 'whatever';
}
Example.prototype.fn_1 = function(){
console.log(this.prop);
return this
}
Example.prototype.fn_2 = function(){
this.prop = 'not whatever';
return this
}
var e = new Example();
e.fn_1() //whatever
e.fn_2().fn_1() //not whatever
Here's a fiddle http://jsfiddle.net/BFm2V/
If you're not using EcmaScript5, I'd recommend using Underscore's (or LoDash's) bind function.
In addition to the other answers given here, if you don't have an ES5-ready browser, you can create your own "permanently-bound function" quite simply with code like so:
function boundFn(thisobj, fn) {
return function() {
fn.apply(thisobj, arguments);
};
}
Then use it like this:
var Example = (function() {
function Example() {
var privateFunction = boundFn(this, function() {
// "this" inside here is the same "this" that was passed to boundFn.
console.log(this);
});
this.publicFunction = function() {
privateFunction();
}
}
return Example;
}()); // I prefer this order of parentheses
Voilà -- this is magically the outer context's this instead of the inner one!
You can even get ES5-like functionality if it's missing in your browser like so (this does nothing if you already have it):
if (!Function.prototype.bind) {
Function.prototype.bind = function (thisobj) {
var that = this;
return function() {
that.apply(thisobj, arguments);
};
}:
}
Then use var yourFunction = function() {}.bind(thisobj); exactly the same way.
ES5-like code that is fully compliant (as possible), checking parameter types and so on, can be found at mozilla Function.prototype.bind. There are some differences that could trip you up if you're doing a few different advanced things with functions, so read up on it at the link if you want to go that route.
I would say assigning self to this is a common technique:
function Example() {
var self = this;
function privateFunction() {
console.log(self);
}
self.publicFunction = function() {
privateFunction();
};
}
Using apply (as others have suggested) also works, though it's a bit more complex in my opinion.
It might be beyond the scope of this question, but I would also recommend considering a different approach to JavaScript where you actually don't use the this keyword at all. A former colleague of mine at ThoughtWorks, Pete Hodgson, wrote a really helpful article, Class-less JavaScript, explaining one way to do this.
I am creating an AJAX API for a web service and I want to be able to call jQuery-like accessors.
jQuery seems to be able to execute 'jQuery' as a function, but also use it to directly access the object that is the result of the function EG:
jQuery();
jQuery.each({});
This is the trick that I can't seem to pull off:
myAPI('foo'); //output: 'foo'
myAPI('foo').changeBar(); //output: 'foo' 1
myAPI.changeBar(); //Error: not a function
I have seen the answers to similar questions, which are helpful, but don't really answer my question.
#8734115 - Really interesting, but you can't access the methods that were set by f.prototype.
#2953314 - Uses Multiple operations to create object instead of a single function.
here is my code:
(function(window) {
var h = function(foo) {
// The h object is actually just the init constructor 'enhanced'
return new h.fn.init(foo);
};
/**
* Methods defined at protoype.
*/
h.fn = h.prototype = {
constructor: h,
init: function(foo) {
console.log(foo);
return this;
},
splice : function () {},
length : 0,
bar : 0,
changeBar : function() {
this.bar++;
return this.bar;
}
};
h.fn.init.prototype = h.fn;
//Publish
window.myAPI =h;
}( window));
I'm sure I'm missing something simple :(
What jQuery is doing there is using jQuery as both a function and as a pseudo-namespace. That is, you can call jQuery: var divs = jQuery("div"); and you can use properties on it, e.g.: jQuery.each(...);.
This is possible because in JavaScript, functions are first-class objects, and so you can add arbitrary properties to them:
function foo() {
alert("Foo!");
}
foo.bar = function() {
alert("Bar!");
};
foo(); // "Foo!"
foo.bar(); // "Bar!"
That's literally all there is to it.
Within the call to bar, this will be the foo function (because this is determined entirely by how a function is called, not where it's defined). jQuery doesn't use this to refer to itself (usually it uses this to refer to DOM elements, sometimes to other things like array elements; when referring to itself, since it's a single thing, it just uses jQuery).
Now, you might want to ensure that your functions have proper names (whereas the function I assigned to bar above is anonymous — the property has a name, but the function does not). In that case, you might get into the module pattern:
var foo = (function() {
function foo() {
alert("Foo!");
}
function foo_bar() {
alert("Bar!");
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
That pattern also has the advantage that you can have private data and functions held within the scoping function (the big anonymous function that wraps everything else) that only your code can use.
var foo = (function() {
function foo() {
reallyPrivate("Foo!");
}
function foo_bar() {
reallyPrivate("Bar!");
}
function reallyPrivate(msg) {
alert(msg);
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
reallyPrivate("Hi"); // Error, `reallyPrivate` is undefined outside of the scoping function
In your code, you're assigning things to the prototype property of the function. That only comes into play when the function is called as a constructor function (e.g., via new). When you do that, the object created by new receives the function's prototype property as its underlying prototype. But that's a completely different thing, unrelated to what jQuery does where it's both a function and a pseudo-namespace.
You do not need any of that weirdness, to use stuff like $.each
you just attach functions to the function object instead
of the prototype object:
function Constructor() {
if (!(this instanceof Constructor)) {
return new Constructor();
}
}
Constructor.prototype = {
each: function() {
return "instance method";
}
};
Constructor.each = function() {
return "static method";
};
var a = Constructor();
a.each(); //"instance method"
Constructor.each(); //"static method"
How is it that jQuery can do $("#foo").addClass("bar") and $.ajax()?
I'm creating a micro javascript framework and want to create a new instance of an object, such as $("#hello"). With this object there are associated methods, such as addClass, css, etc, just like with jQuery. So I could do something like
$("#foo").addClass("remove").css("color", "red");
I have been successful in creating this. However, when I want to call a method from this object, such as $.ajax, the constructor function is overwritten, and I can call $.ajax, but not $("#foo").
Basically, how can jQuery do both?
$ = function(arg) { console.log("$ function called with " + arg); }
$.ajax = function(arg) {console.log("$.ajax called with " + arg);}
$('foo');
$.ajax('bar');
http://jsfiddle.net/ac7nx/
I don't think there's any magic here. $ is just a name for the global function. Just keep in mind that in javascript, functions are first class objects that can have their own properties, including sub-functions, which is what $.ajax is.
Since you mentioned the constructor function, I should note that there are no OO objects being used here, just regular functions (no new keyword), so constructor functions don't play into this. If you are using the new keyword, that is probably where you are getting confused. If you want $('#foo') to return a new object, then inside the $ function's code you should create a new object using new and return that, which is what jQuery does, but the $ function itself is not a constructor and should not be called with new. Or in the case of something like $('#someID'), inside that function jQuery is getting an element object from the DOM and then returning that object, but still $ is just a regular function whose return value is an object, not a constructor function.
OK, the $ function is not only a function but an object, like all functions. So it can have methods. That's all that ajax is, a method of the $ function. So we can start off by doing this:
$ = function(obj) {
// some code
};
$.ajax = function (arg1, arg2) {
// some ajax-y code
};
So far so good. Now, what on earth do we put in the $ function? Well it has to return an object and that object has to have some nice methods defined on it. So we'll need a constructor function (to give us new objects) and a prototype (to provide the nifty methods for those objects).
$ = function(obj) {
var myConstructor = function (obj) {
this.wrappedObj = obj;
};
myConstructor.prototype = {
niftyMethod: function () {
// do something with this.wrappedObj
return this; // so we can chain method calls
},
anotherNiftyMethod: function (options) {
// do something with this.wrappedObj and options
return this;
}
};
return new myConstructor(obj);
};
So there we have it. We can do this:
var mySnazzObject = $("whatever");
mySnazzObject.niftyMethod().anotherNiftyMethod(true);
And we can do this:
$.ajax("overthere.html", data);
Obviously jQuery does a heck of a lot more than that, and it does it in some really impressive ways, but that's the general idea.
UPDATE: AS #Raynos was kind enough to observe without supplying a constructive answer, my original code would create the prototype ad infinitum. So we make use of an anonymous autoexecuting function to declare the constructor and prototype separately:
(function () {
var myConstructor = function (obj) {
this.wrappedObj = obj;
};
myConstructor.prototype = {
niftyMethod: function () {
// do something with this.wrappedObj
return this; // so we can chain method calls
},
anotherNiftyMethod: function (options) {
// do something with this.wrappedObj and options
return this;
}
};
var $ = function(obj) {
return new myConstructor(obj);
};
$.ajax = function (arg1, arg2) {
// some ajax-y code
};
window.$ = $;
}());
Two different things:
$.ajax is a prototyped function of jQuery called ajax.
While $('foo') is a call of the jQuery function and depending on the type of foo it reacts in different ways. At http://api.jquery.com/jQuery you can see that jQuery (almost the same as $) can react on three different types: selectors, html or callbacks.
You can imitate the magic jQuery behaviour as following:
//define
var _$ = {};
var $ = function(selector) {
_$.html = function(args) {
alert("Doing the method 'html' with arguments " + args
+ " for selector " + selector);
return _$; //needed for pipeline
};
return _$;
};
$.ajax = function(args){alert("Doing the method 'ajax' "); }
//and try
$("selector1").html("args1").html("args2");
$.ajax("args2");