How to get the parent / parent object instance in a javascript function?

9

I'm implementing a method extension library of prototype , and if I do it simply everything works perfectly as you can see in the simple example below:

String.prototype.append = function(value) {
  // aqui o this é a instancia da String. Ok!
  return this.toString() + value;
};

document.getElementById('result').textContent = "Concatena com ".append("isto!");
<p id="result">
</p>

But to avoid overwriting methods of prototype , I created an object within prototype to register these methods, but with that the scope of the method changes and the this is no longer a reference to String , as can be seen in the following example:

String.prototype.extencion = {
  append: function(value) {
    // aqui o this não é mas uma instancia da String. Fail =(!
    // Como pegar a instancia do objecto pai?
    return this.toString() + value;
  }
};

document.getElementById('result').textContent = "Concatena com ".extencion.append("isto!");
<p id="result"></p>

Question

Is it possible to retrieve the instance of the parent object in a function in the child object?

    
asked by anonymous 09.10.2015 / 21:01

2 answers

10

Unfortunately, what you want is not possible. The object you created is a member of the String prototype, so the most you could (although I believe even this is not possible) would be to get a reference to this prototype - but not to the string that gave access to it. For once the chain of prototypes in the access to the field went up:

"Concatena com ".extencion

You have already lost the reference to the original string forever ...

In the case of methods the reference still exists in the form of this , but not in access to fields, so I usually use closures when I need to do something like this (although I do not know if it's a good idea to do this or not). Example:

String.prototype.extencion = function() {
  return {
    append: (function(value) {
      return this.toString() + value;
    }).bind(this) // aqui o this é amarrado com o objeto original
  };
};

document.getElementById('result').textContent = "Concatena com ".extencion().append("isto!");
<p id="result"></p>

One disadvantage of this method is that it creates a new object with each function invocation ... You could save it for each instance, but there is a waste of memory that can become significant (depending on how you use it ). That's why I said I do not know if it's a good idea. A middle ground - not so convenient, but without the problems mentioned above - is to do in the "jQuery style":

var extensoesString = {
  append: function(_, value) {
    return this.toString() + value;
  }
};

String.prototype.extencion = function(funcao) {
  return extensoesString[funcao].apply(this, arguments);
};

document.getElementById('result').textContent = "Concatena com ".extencion("append", "isto!");
<p id="result"></p>
    
09.10.2015 / 21:26
4

You can create a parallel Type ( superString in the example below) and put your methods there. To do this copy the prototype of String and pass your strings by the new Type you create. The idea is like this:

var superString = (function () {
    // constructor
    function MyString(str) {
        this._str = str;
    }

    // criar uma cópia para não escrever métodos na String nativa
    MyString.prototype = Object.create(String.prototype);

    // funcionalidade "append"
    MyString.prototype.append = function (value) {
        return this.toString() + value;
    };

    // é preciso sobreescrever estes métodos... 
    MyString.prototype.toString = function () {
        return this._str;
    };

    MyString.prototype.valueOf = function () {
        return this._str;
    };

    Object.defineProperty(MyString.prototype, 'comprimento', {
        get: function () {
            return this._str.length;
        }
    });
    return MyString;
})();


var str = new superString('Concatena com ');

document.getElementById('result').textContent = str.append('isto!');
console.log(str.comprimento); // 14

jsFiddle: link

Some notes:

  • I had to rewrite the native methods .valueOf () and .toString () to work otherwise it would give error.
  • To re-create a .length property is theoretically possible, but Chrome goes into an infinite loop, so I created a comprimento property with a getter to give what is expected.

Another solution using the same idea, regardless of the prototype of String would already allow the property .length and would be simpler:

var superString = (function () {
    // constructor
    function MyString(str) {
        this._str = str;
    }

    // funcionalidade "append"
    MyString.prototype.append = function (value) {
        return this._str.toString() + value;
    };

    Object.defineProperty(MyString.prototype, 'length', {
        get: function () {
            return this._str.length;
        }
    });
    return MyString;
})();


var str = new superString('Concatena com ');

document.getElementById('result').textContent = str.append('isto!');
console.log(str.length); // 14

jsFiddle: link

    
10.10.2015 / 08:26