JavaScript getter para todas as propriedades

Resumindo: Estou em uma situação em que gostaria de um getter no estilo PHP, mas em JavaScript.

Meu JavaScript está sendo executado apenas no Firefox, portanto, o JS específico do Mozilla é OK para mim.

A única maneira que eu posso encontrar para fazer um JS getter requer especificar seu nome, mas eu gostaria de definir um getter para todos os nomes possíveis. Não tenho certeza se isso é possível, mas gostaria muito de saber.

O mais próximo que você pode encontrar é __noSuchMethod__ , que é o equivalente a JavaScript do __call () do PHP.

Infelizmente, não há equivalente de __get / __ set, o que é uma pena, porque com eles poderíamos ter implementado __noSuchMethod__, mas ainda não vejo uma maneira de implementar propriedades (como em C #) usando __noSuchMethod__.

var foo = { __noSuchMethod__ : function(id, args) { alert(id); alert(args); } }; foo.bar(1, 2); 

Proxy pode fazer isso! Estou tão feliz que isso existe !! Uma resposta é dada aqui: Existe um equivalente javascript do método __getattr__ do python? . Para reformular minhas próprias palavras:

 var x = new Proxy({},{get(target,name) { return "Its hilarious you think I have "+name }}) console.log(x.hair) // logs: "Its hilarious you think I have hair" 

Proxy para a vitória! Confira os documentos do MDN: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Funciona em chrome, firefox e node.js. Desvantagens: não funciona no IE – freakin IE. Em breve.

Se você está codificando no ES6, você pode combinar proxy e class para ter um código bonito como o php :

 class Magic { constructor () { return new Proxy(this, this); } get (target, prop) { return this[prop] || 'MAGIC'; } } 

isso se liga ao manipulador, então você pode usar isso em vez de alvo.

Nota: ao contrário do PHP, o proxy lida com todos os pedidos de propriedade.

 let magic = new Magic(); magic.foo = 'NOT MAGIC'; console.log(magic.foo); // NOT MAGIC console.log(magic.bar); // MAGIC 

Você pode verificar quais navegadores suportam o proxy http://caniuse.com/#feat=proxy e a class http://caniuse.com/#feat=es6-class . O nó 8 suporta ambos.

O Javascript 1.5 tem açúcar sintático getter / setter . É explicado muito bem por John Resig aqui

Não é genérico o suficiente para uso na web, mas certamente o Firefox os tem (também Rhino, se você quiser usá-lo no lado do servidor).

Se você realmente precisa de uma implementação que funcione, você pode “enganar” seu caminho ao testar o segundo parâmetro contra undefined , isso também significa que você pode usar get para definir o parâmetro.

 var foo = { args: {}, __noSuchMethod__ : function(id, args) { if(args === undefined) { return this.args[id] === undefined ? this[id] : this.args[id] } if(this[id] === undefined) { this.args[id] = args; } else { this[id] = args; } } }; 

Se você está procurando por algo como a function __get() do PHP, eu não acho que o Javascript forneça tal constructo.

O melhor que posso pensar é fazer um loop através dos membros não-funcionais do object e então criar uma function “getXYZ ()” correspondente para cada um.

No código falso pseudo-ish:

 for (o in this) { if (this.hasOwnProperty(o)) { this['get_' + o] = function() { // return this.o -- but you'll need to create a closure to // keep the correct reference to "o" }; } } 

Acabei usando uma resposta do nickfs para construir minha própria solução. Minha solução criará automaticamente funções get_ {propname} e set_ {propname} para todas as propriedades. Ele verifica se a function já existe antes de adicioná-los. Isso permite que você substitua o método get ou set padrão com nossa própria implementação, sem o risco de ser sobrescrito.

 for (o in this) { if (this.hasOwnProperty(o)) { var creategetter = (typeof this['get_' + o] !== 'function'); var createsetter = (typeof this['set_' + o] !== 'function'); (function () { var propname = o; if (creategetter) { self['get_' + propname] = function () { return self[propname]; }; } if (createsetter) { self['set_' + propname] = function (val) { self[propname] = val; }; } })(); } }