Javascript: What Does This Code Do?
I apologize in advanced if this question is too broad. In fact it's 4 different questions, but all related to the same piece of code, and I think they all revolve around the same principle.
I decided today, after using JS for years, to actually start learning how JS works instead of treating it like C that runs in the browser. So I starting digging into the jQuery code to see how real JS developers use the langauge. That's when I found a block of code that looks like the code below. Note, I took this code off another stacked post here In Javascript, can you extend the DOM? . So that 开发者_开发知识库doesn't mean the person that wrote this code even knew what he was talking about.
var myDOM = (function(){ // #1
var myDOM = function(elems){ // #2
return new MyDOMConstruct(elems);
},
MyDOMConstruct = function(elems) {
this.collection = elems[1] ? Array.prototype.slice.call(elems) : [elems];
return this; // #3
};
myDOM.fn = MyDOMConstruct.prototype = {
forEach : function(fn) {
var elems = this.collection;
for (var i = 0, l = elems.length; i < l; i++) {
fn( elems[i], i );
}
return this;
},
addStyles : function(styles) {
var elems = this.collection;
for (var i = 0, l = elems.length; i < l; i++) {
for (var prop in styles) {
elems[i].style[prop] = styles[prop];
}
}
return this;
}
};
return myDOM; // #4
})();
1 Why declare the function using var myDOM = (function() {})(); instead of var myDOM = function() {};
2 Why declare another function inside of the myDOM function with the exact same name? Why not put all the inner myDOM's logic inside the outer myDOM function?
3 Why explicitly return "this"? That would have been done automatically, correct?
4 What's going on here? Is it returning the inner myDOM's constructor? If so, why?
Update
So most of it makes sense now. Regarding #1, I thought myDOM was being assigned the function defined after the =, but it's not. It's being assigned whatever that function returns. Which just happens to be a function.
I'm still not clear on #3. Yes, I understand using the function like this
console.log(MyDomConstruct('foo'))
Would display 'undefined'. But that's not how it's being used. A few lines up is this
return new MyDomConstruct(elems);
I can understand explicity returning "this" if the statement went like this
return MyDomConstruct(elems);
But that's not the case.
Why declare the function using var myDOM = (function() {})(); instead of var myDOM = function() {};
That is a such called self-invoking anonymous function
or self-executing anonymous function
. It does exactly that, it calls itself at runtime. You'll also see the pattern:
(function($){
}(jQuery));
quite alot in the jQuery world. It's the same thing, at runtime the function calls itself and guarantees that the $
sign has a reference to jQuery
object within the function body.
In your snippet, the function invokes itself and returns myDOM
, a functions reference.
Why declare another function inside of the myDOM function with the exact same name? Why not put all the inner myDOM's logic inside the outer myDOM function?
That is just a convention. It could be called whatever you want it to be, maybe the author thought it is convinient to do this. The reason for this pattern is privacy & security. By returning the inner myDOM
reference a closure
is created. So the after declaring something like
var mytest = myDOM([]);
you won't have access to MyDOMConstruct
, but your inner function do have access. That way you can protect your methods and variables. It's also called the method pattern
. Always a good read in this context Douglas Crockford: Javascript the good parts
.
Why explicitly return "this"? That would have been done automatically, correct?
No, a function will return the undefined
value by default. By explicitly return this
you can chain
the methods like (from the above example call):
mytest.forEach([]).addStyles([]); ...
since each method is returning the object of invocation, in this case myDOM
.
What's going on here? Is it returning the inner myDOM's constructor? If so, why?
I hope that should be clear at this point.
Edit
Based on your update:
new MyDOMConstruct();
produces a new object that inherits
from
MyDOMConstruct.prototype
Without the new keyword
the this
would not be bound to the new object. Instead it would be bound to the global object (window) and you would access global variables using this
.
1. Why declare the function using var myDOM = (function() {})();
instead of var myDOM = function() {};
The form used is a self executing function. This means that myDOM is set to whatever the function returns. The second form sets myDOM to the function but doesn't execute the function right away.
var myDOM = (function() { // <== This is a function that does something
// Something
})(); // The function is executed right HERE with ().
2. Why declare another function inside of the myDOM function with the exact same name? Why not put all the inner myDOM's logic inside the outer myDOM function?
Because you are returning the inner myDOM function at the end.... so the naming actually makes sense eventhough it is at first confusing. This is often used to create private variables in JS. Since the inner function will have access to the scope it is enclosed in (the self executing anonymous function) but the user will not.
var myDOM = (function() { // <== This is a function that is going to return
// a function / object
var myDOM = function() { // <== We're going to return this
... // The outer myDom will be set to it
}; // So it's actually helpful to name
// it the same for clarity.
return myDOM;
})();
// Now we can access that inner object by using the outer myDOM.
// We could access the inner object using myDOM even if the inner object
// was named otherTHING... It's confusing to acces something
// called otherTHING in the code by
// writing myDOM().... so better name the inner returned function
// myDOM as well.
So the inner object could be named anything, and it could be executed with myDOM()
, but if you name the inner function blah
yet you can still execute it by using myDOM()
... that's not very clear... much better to name it the same.
3. Why explicitly return "this"? That would have been done automatically, correct?
No, if you don't write anything, Javascript automatically returns undefined
. The MDC reference:.
Returning this
is often used for preserving the context of a method. It used to make the chaining of methods ( $(here).is().a().chain().of().methods()
) possible. So that a method down the chain knows the context it's operating in.
Just one more note to the self-executing anonymous function. Wrapping some pieces of JavaScript in a (function() { })();
block is a way of creating a private namespace. Everything you do inside the inner function will be function private except for the value returned (in this case myDOM
).
That is you can savely do things like
var counter = (function() {
var i = 0;
var counter = function() {
alert(i++);
return i;
}
return counter;
})();
counter(); // will alert 0
counter(); // will alert 1
// ... and so on
to keep some inner state secret from outside the function. The second reason, as already stated in other posts is that it will not pollute the global namespace with the variable i
. That is the case why it is best practice to use these kind of functions in jQuery plugin development.
same as this one:
(function () {
function b(a) {
return new c(a)
}
function c(a) {
this.a = a[1] ? Array.prototype.slice.call(a) : [a];
return this
}
b.b = c.prototype = {};
return b
})();
hope that helps... :)
for example: var fn = (function(){ return function(){ alert(11)}; })(); when the code run,now the fn = function(){ alert(11)}; try it!!!
精彩评论