What is the difference between these two implementations?

20

I was reading some articles on patterns and I was struck by a doubt in the following two examples. Suppose I have a single function that returns me an element by means of the ID sent as argument. The first one:

var utils = (function(){
    var self = {};

    self.by = function(id){
        return document.getElementById(id);
    };

    return {
        by: self.by
    };
})();

Where could I call the by function as follows:

utils.by("campoTexto").innerHTML = "Algum Texto";

Now, a second example:

var utils2 = (function(){
    return {
      by: function(id){
          return document.getElementById(id);
      }
    };
})();

Where could I call the by function as follows:

utils2.by("campoTexto").innerHTML = "Algum Texto";

My question is: What's the difference between these two implementations? In the first one, the function is implemented outside return while in the second it is implemented inside return , what does this change in 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>
    
asked by anonymous 27.03.2015 / 16:55

1 answer

14

It does not change anything in the example you gave ... but it can be useful in other situations.

When does it make a difference?

This may be necessary if you want to reference the object self from within the by function, without relying on this ... or else associate 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 does not change, then it will be necessary:

  • use self within by :

    by: function() { self.qualquerCoisa... ; }
    

    In this case, even using call or apply to call the by method, still so self would not be changed, whereas using this would change the result.

  • or by.bind(self) :

    by: (function() { this.qualquerCoisa... ; }).bind(self)
    

    In this case, this will always be equal to self , nor even using call / apply you can change the behavior.

Note: that this also changes when you copy a reference to a function from one place to another, not only 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 does nothing change in the example of the question?

As I said, in your example, there is no difference from one to the other. This is due to the fact that nothing will take a reference of self out of that function.

  • self is not enclosed in the by function (not used in a closure)
  • self is not copied to the returned object

This means that nothing will remain of self , since no reference will remain 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/>");
}
    
27.03.2015 / 17:07