//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.