What is the difference between these two implementations?

Asked

Viewed 261 times

20

I was reading some articles about Patterns and I had a doubt in the following two examples. Suppose I have a single function that returns an element to me through the ID sent as argument. The first:

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

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

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

Where I could call the function by as follows:

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

Now, a second example:

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

Where I could call the function by as follows:

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

My question is: What is the difference between these two implementations? In the first, the function is implemented outside the return while in the second is implemented within the return, what this changes 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>

1 answer

14


Nothing changes in the example you gave... but it can be useful in other situations.

When it makes a difference?

This may be necessary if you want to refer to the object self from within the function by, without depending on the this... or else associate the this more permanently using bind (e. g. 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 inside by:

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

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

  • or else by.bind(self):

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

    In this case, this will always be equal to self, not even using call/apply it is possible to change the behavior.

Note: that the this also changes, when you copy a reference to a function from one place to another, not only 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";

Because nothing changes in the example of the question?

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

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

That means nothing will be left of self, because no reference will remain for him.

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/>");
}

  • 1

    What a knot in my poor little head...

  • @Jorgeb. tell me what your difficulty is so I can improve the answer.

  • What did you mean if I wanted to use self.exemplo inside by was possible in the first implementation is that the advantage?

  • 2

    Exactly. The reason for such an advantage is that this can change. But if the intention is to use something that does not change, then it will be necessary to use self inside by, or else by.bind(self).

  • 1

    I copied my previous comment to the answer itself, and gave an organized one... now I think it got better.

  • I think so :)

  • 1

    When used (for example) self inside the body of by, this is called closure. The meaning in Portugese is "enclosure", and if it is because the function traps the variable within it, even if it leaves the context in which it was declared, the variable remains within the function.

  • 1

    In the first case self may be different from this. If by were defined as such: function(){return self===this;} the result could be false depending on how the function will be used (e. g. utils2.by() // this == utils, so this != self). On the other hand, if using bind, Yes, it will never be different. If by is defined as (function(){return self===this;}).bind(self) the result would always be positive (if the closed variable was not reset, type self={novaDefinicao:"self redefinido"}).

  • 1

    I added a few code snippets to demonstrate how the this can be changed and in what ways it is possible to maintain the self original.

  • Miguel, I meant, for example: Supposing I’m going to create the function by (limiting only to creation) within utils. Create it using self.by(...) would be the same thing as this.by(...)? Both are a function that belongs to utils?

  • You’re talking about the difference between these codes: self.by=function(){} and this.by=function(){} ?

  • @Miguelangelo

  • 1

    The option using this would only work if the function was called with the operator new: var modulo = new (function() { this.by = function(id){ }; })();

Show 8 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.