Question:
I was reading some articles about patterns and I got a question in the two examples below. Suppose I have a single function that returns me an element via the ID sent as an argument. The first:
var utils = (function(){
var self = {};
self.by = function(id){
return document.getElementById(id);
};
return {
by: self.by
};
})();
Where could I call the by
function like this:
utils.by("campoTexto").innerHTML = "Algum Texto";
Now for a second example:
var utils2 = (function(){
return {
by: function(id){
return document.getElementById(id);
}
};
})();
Where could I call the by
function like this:
utils2.by("campoTexto").innerHTML = "Algum Texto";
My question is: What is the difference between these two implementations? In the first one, the function is implemented outside the return
while in the second one it is implemented inside the return
, what does that change in the code?
var utils = (function(){
var self = {};
self.by = function(id){
return document.getElementById(id);
};
return {
by: self.by
};
})();
var utils2 = (function(){
return {
by: function(id){
return document.getElementById(id);
}
};
})();
utils.by("a").innerHTML = "Usando 'utils'...";
utils2.by("b").innerHTML = "Usando 'utils2'...";
<p id='a'></p>
<p id='b'></p>
Answer:
It doesn't change anything in the example you gave… but it can be useful in other situations.
When does it matter?
This may be necessary if you want to reference the self
object from within the by
function, without relying on this
… or else bind this
more permanently using bind
(eg by.bind(self)
).
The reason for this advantage is that this
can change. But if the intention is to use something that doesn't change, then it will be necessary:
-
use
self
insideby
:by: function() { self.qualquerCoisa... ; }
In this case, even using
call
orapply
to call theby
method,self
would still not be changed, whereas usingthis
would change the result. -
or else
by.bind(self)
:by: (function() { this.qualquerCoisa... ; }).bind(self)
In this case,
this
will always be equal toself
, not even usingcall
/apply
is possible to change the behavior.
Note that this
also changes when you copy a reference to a function from one place to another, not just when using call
/ apply
:
var utils2 = ...;
myUtils.by = utils2.by;
// o `this` passado para o `by` abaixo, será `myUtils` e não `utils2`
myUtils.by("campoTexto").innerHTML = "Algum Texto";
Why doesn't it change anything in the question example?
As I said, in your example, there is no difference between them. This is because nothing will take a self
reference outside of this function.
-
self
is not enclosed in theby
function (not used in a closure) -
self
is not copied to the returned object
This means that there will be nothing left of self
, as no reference will be left for it.
Snippets to test the possibilities
// self original será enclausurado e retornado var modulo = (function() { var self = {}; self.by = function(id) { return this === self; }; return self; })(); escrever(modulo.by()); // true var outro = { by: modulo.by }; escrever(outro.by()); // false escrever(modulo.by.call(outro)); // false // self original será enclausurado, mas não retornado var modulo = (function() { var self = {}; self.by = function(id) { return this === self; }; return { by: self.by }; })(); escrever(modulo.by()); // false var outro = { by: modulo.by }; escrever(outro.by()); // false escrever(modulo.by.call(outro)); // false // self original será enclausurado, alterado e depois retornado var modulo = (function() { var self = {}; self.by = function(id) { return this === self; }; self = { by: self.by }; return self; })(); escrever(modulo.by()); // true var outro = { by: modulo.by }; escrever(outro.by()); // false escrever(modulo.by.call(outro)); // false // self original será enclausurado em função com bind e retornado var modulo = (function() { var self = {}; self.by = (function(id) { return this === self; }).bind(self); return self; })(); escrever(modulo.by()); // true var outro = { by: modulo.by }; escrever(outro.by()); // true escrever(modulo.by.call(outro)); // true // self original será enclausurado em função com bind, mas não retornado var modulo = (function() { var self = {}; self.by = (function(id) { return this === self; }).bind(self); return { by: self.by }; })(); escrever(modulo.by()); // true var outro = { by: modulo.by }; escrever(outro.by()); // true escrever(modulo.by.call(outro)); // true // self original será enclausurado em função com bind, alterado e depois retornado var modulo = (function() { var self = {}; self.by = (function(id) { return this === self; }).bind(self); self = { by: self.by }; return self; })(); escrever(modulo.by()); // false var outro = { by: modulo.by }; escrever(outro.by()); // false escrever(modulo.by.call(outro)); // false function escrever(valor) { document.write(valor+"<br/>"); }