Como obter a instância do objeto superior/pai em uma function javascript? – javascript

Pergunta:


Estou implementando uma biblioteca de extensão de métodos do prototype, e se faço da forma simples tudo funciona perfeitamente como podem verificar no simples exemplo a seguir:

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>

Mas para evitar sobrescrever métodos do prototype, criei um objeto dentro do prototype para registrar esses métodos, mas com isso o escopo do método se modifica e o this não é mais uma referencia para a String, como pode ser verificado no exemplo a seguir:

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>

Pergunta

É possível recuperar a instância do objeto pai em uma function no objeto filho?

Autor da pergunta Fernando Leal

mgibsonbr

Infelizmente isso que você quer não é possível. O objeto que você criou é um membro do protótipo de String, então o máximo que você poderia (embora eu acredite que nem isso seja possível) seria obter uma referência a esse protótipo – mas não à string que originou o acesso a ele. Pois uma vez que se subiu a cadeia de protótipos no acesso ao campo:

"Concatena com ".extencion

Já se perdeu a referência pra string original para sempre…

No caso dos métodos a referência ainda existe na forma do this, mas não no acesso a campos, de modo que eu costumo usar closures quando preciso fazer algo desse tipo (embora não saiba se é uma boa ideia mesmo fazer isso ou não). Exemplo:

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>

Uma desvantagem desse método é que ele cria um objeto novo a cada invocação de função… Você poderia salvá-la para cada instância, mas aí há um desperdício de memória que pode se tornar significativo (dependendo do modo como se usa). Por isso disse não saber se é uma boa ideia. Um meio termo – não tão conveniente, mas sem os problemas citados acima – é fazer no “estilo jQuery”:

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>

Podes criar um Type paralelo (superString no exemplo em baixo) e colocar os teus métodos alí. Para isso copias o prototype de String e passas as tuas strings pelo novo Type que crias-te. A ideia é assim:

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: http://jsfiddle.net/f2gzm6dx/

Algumas notas:

  • Tive de re-escrever os métodos nativos .valueOf () e .toString () para funcionar senão dava erro.
  • para re-criar uma propriedade tipo .length é teoréticamente possivel, mas o Chrome entra num loop infinito, assim criei uma propriedade comprimento com um getter para dar o que é esperado.

Outra solução usando a mesma ideia, sem importar o prototype de String já permitiria a propriedade .length e seria mais simples:

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: http://jsfiddle.net/93xc49Lm/

Fonte

Related Posts:

Qual a diferença entre AppCompatActivity e Activity? – android android-activity
Pergunta: Qual a diferença da AppCompatActivity para Activity ? A partir de qual versão a AppCompatActivity foi adicionada ao Android? Autor da pergunta Luhhh A diferença reside ...
Como abreviar palavras em PHP? – php string
Pergunta: Possuo informações comuns como nome de pessoas e endereços, e preciso que elas contenham no máximo 30 caracteres sem cortar palavras. Exemplo: 'Avenida Natalino João Brescansin' ...
Qual é a finalidade de um parêntese vazio numa declaração Lambda? – c# expressões-lambda característica-linguagem
Pergunta: Criei um exemplo de uma declaração Lambda sem argumentos, entretanto, estou com duvidas referente a omissão do parêntese vazio () na declaração. Veja o exemplo: class ...
Boas práticas para URI em API RESTful – api rest restful
Pergunta: Estou com dúvida em relação às URIs de alguns recursos da api que estou desenvolvendo. Tenho os recursos projetos e atividades com relação 1-N, ...
Dúvidas sobre a integração do MySQL com Java – java mysql netbeans
Pergunta: Estou criando um sistema no NetBeans, utilizando a linguagem Java e o banco de dados MySQL. Escrevi o seguinte código para realizar a conexão ...
Qual é a finalidade da pasta Model do framework Inphinit? – php inphinit
Pergunta: No Inphinit micro-framework existe a pasta Model que fica dentro da pasta application, e nela é onde ficam as classes, mas eu estou muito ...
Uso do ‘@’ em variáveis – javascript typescript coffeescript
Pergunta: Vejo em algumas linguagens que compilam para javascript, como TypeScript e CoffeeScript, o uso do @ em variáveis, como também, casos em que o ...
Qual tamanho máximo um arquivo JSON pode ter? – json arquivo
Pergunta: Vou dar um exemplo para conseguir explicar minha duvida: Preciso recuperar informação de imagens vindas de uma API, esse banco de imagens me retorna JSON's ...
O que é Teste de Regressão? – terminologia engenharia-de-software testes
Pergunta: Na matéria de Teste de Software o professor abordou um termo chamado Teste de Regressão, isto dentro da disciplina de teste de software. Sendo ...
O que é um construtor da linguagem? – php característica-linguagem
Pergunta: Em PHP, já li e ouvi várias vezes a respeito dos Construtores da Linguagem. Os casos que sempre ouvi falar deles foi em casos ...
Função intrínseca para converter numérico para string – cobol
Pergunta: Estou a tentar saber se existe alguma função intrínseca do COBOL para converter um data numérico para string sem precisar usar a cláusula REDEFINES: ( ...
Porque usar implements? – java android
Pergunta: Qual a diferença entre usar btn.setOnClickListener(new OnClickListener() { e public class MainActivity extends Activity implements OnClickListener{ Estive fazendo um curso de Android e meu professor falou que ...
O que é XHTML e quando deve ser usado? – html xml xhtml
Pergunta: O que eu sei é que o XHTML precisa ser XML válido. Isso implica, por exemplo, que todas as tags precisam ser fechadas. Por ...
Uma placa aceleradora de vídeo pode melhorar o desempenho não-gráfico? [fechada] – desempenho
Pergunta: Para desenvolver em Ruby on Rails, eu utilizo aqui uma máquina virtual do VirtualBox com Ubuntu Server 14.04 sem interface gráfica instalada. Recentemente descobri uma ...
Concat() VS Union() – c# .net
Pergunta: Qual a diferença entre Concat() e Union() ? Quando usar Concat() e quando usar Union() ? Somente pode ser usado em list ? ...

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *