Não consigo encontrar uma maneira de sobrecarregar o operador [] em javascript. Alguém aí sabe?
Eu estava pensando nas linhas de ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
ou não estou olhando para as coisas certas.
javascript
operator-overloading
slyprid
fonte
fonte
MyClass
objeto um array. Você pode copiar as chaves e valores demyArray
para o seuvar myObj = new MyClass()
objeto.Respostas:
Você não pode sobrecarregar operadores em JavaScript.
Foi proposto para ECMAScript 4, mas rejeitado.
Eu não acho que você verá isso tão cedo.
fonte
Object arg1: a arg2: b arg3: c
comoObject["arg1:arg2:arg3:"](a,b,c)
. Então você pode termyObject["[]"](1024)
: PVocê pode fazer isso com ES6 Proxy (disponível em todos os navegadores modernos)
var handler = { get: function(target, name) { return "Hello, " + name; } }; var proxy = new Proxy({}, handler); console.log(proxy.world); // output: Hello, world
Verifique os detalhes no MDN .
fonte
target[name]
no getter, OP está apenas mostrando os exemplos[]
operador,var key = 'world';
console.log(proxy[key]);
A resposta simples é que o JavaScript permite acesso aos filhos de um objeto por meio dos colchetes.
Então você pode definir sua classe:
MyClass = function(){ // Set some defaults that belong to the class via dot syntax or array syntax. this.some_property = 'my value is a string'; this['another_property'] = 'i am also a string'; this[0] = 1; };
Você poderá então acessar os membros em qualquer instância de sua classe com qualquer uma das sintaxes.
foo = new MyClass(); foo.some_property; // Returns 'my value is a string' foo['some_property']; // Returns 'my value is a string' foo.another_property; // Returns 'i am also a string' foo['another_property']; // Also returns 'i am also a string' foo.0; // Syntax Error foo[0]; // Returns 1 foo['0']; // Returns 1
fonte
foo['random']
que seu código não é capaz de fazer.Use um proxy. Isso foi mencionado em outro lugar nas respostas, mas acho que este é um exemplo melhor:
var handler = { get: function(target, name) { if (name in target) { return target[name]; } if (name == 'length') { return Infinity; } return name * name; } }; var p = new Proxy({}, handler); p[4]; //returns 16, which is the square of 4.
fonte
Como o operador colchetes é, na verdade, um operador de acesso à propriedade, você pode conectá-lo com getters e setters. Para o IE, você terá que usar Object.defineProperty (). Exemplo:
var obj = { get attr() { alert("Getter called!"); return 1; }, set attr(value) { alert("Setter called!"); return value; } }; obj.attr = 123;
O mesmo para o IE8 +:
Object.defineProperty("attr", { get: function() { alert("Getter called!"); return 1; }, set: function(value) { alert("Setter called!"); return value; } });
Para IE5-7 há
onpropertychange
apenas evento, que funciona para elementos DOM, mas não para outros objetos.A desvantagem do método é que você só pode conectar solicitações a um conjunto predefinido de propriedades, não a propriedades arbitrárias sem qualquer nome predefinido.
fonte
obj['any_key'] = 123;
mas o que vejo em seu código, preciso definir setter / getter para qualquer chave (ainda não conhecida). Isso é impossível.Você precisa usar Proxy conforme explicado, mas ele pode ser integrado a um construtor de classe
return new Proxy(this, { set: function( target, name, value ) { ...}};
com isso'. Em seguida, as funções set e get (também deleteProperty) serão acionadas. Embora você obtenha um objeto Proxy que parece diferente, na maioria das vezes funciona perguntar a comparação (target.constructor === MyClass) é o tipo de classe etc. [mesmo que seja uma função onde target.constructor.name é o nome da classe em texto (apenas observando um exemplo de coisas que funcionam ligeiramente diferentes.)]
fonte
Então, você espera fazer algo como var what = MyClassInstance [4]; ? Em caso afirmativo, a resposta simples é que o Javascript não suporta atualmente a sobrecarga do operador.
fonte
uma maneira sorrateira de fazer isso é estendendo a própria linguagem.
passo 1
definir uma convenção de indexação customizada, vamos chamá-la de "[]".
var MyClass = function MyClass(n) { this.myArray = Array.from(Array(n).keys()).map(a => 0); }; Object.defineProperty(MyClass.prototype, "[]", { value: function(index) { return this.myArray[index]; } }); ... var foo = new MyClass(1024); console.log(foo["[]"](0));
passo 2
definir uma nova implementação de avaliação. (não faça assim, mas é uma prova de conceito).
var MyClass = function MyClass(length, defaultValue) { this.myArray = Array.from(Array(length).keys()).map(a => defaultValue); }; Object.defineProperty(MyClass.prototype, "[]", { value: function(index) { return this.myArray[index]; } }); var foo = new MyClass(1024, 1337); console.log(foo["[]"](0)); var mini_eval = function(program) { var esprima = require("esprima"); var tokens = esprima.tokenize(program); if (tokens.length == 4) { var types = tokens.map(a => a.type); var values = tokens.map(a => a.value); if (types.join(';').match(/Identifier;Punctuator;[^;]+;Punctuator/)) { if (values[1] == '[' && values[3] == ']') { var target = eval(values[0]); var i = eval(values[2]); // higher priority than [] if (target.hasOwnProperty('[]')) { return target['[]'](i); } else { return target[i]; } return eval(values[0])(); } else { return undefined; } } else { return undefined; } } else { return undefined; } }; mini_eval("foo[33]");
o acima não funcionará para índices mais complexos, mas pode ser com uma análise mais forte.
alternativo:
em vez de recorrer à criação de sua própria linguagem de superconjunto, você pode compilar sua notação para a linguagem existente e, em seguida, avaliá-la. Isso reduz a sobrecarga de análise para nativa após a primeira vez que você o usa.
var compile = function(program) { var esprima = require("esprima"); var tokens = esprima.tokenize(program); if (tokens.length == 4) { var types = tokens.map(a => a.type); var values = tokens.map(a => a.value); if (types.join(';').match(/Identifier;Punctuator;[^;]+;Punctuator/)) { if (values[1] == '[' && values[3] == ']') { var target = values[0]; var i = values[2]; // higher priority than [] return ` (${target}['[]']) ? ${target}['[]'](${i}) : ${target}[${i}]` } else { return 'undefined'; } } else { return 'undefined'; } } else { return 'undefined'; } }; var result = compile("foo[0]"); console.log(result); console.log(eval(result));
fonte
Podemos obter proxy | definir métodos diretamente. Inspirado por isso .
class Foo { constructor(v) { this.data = v return new Proxy(this, { get: (obj, key) => { if (typeof(key) === 'string' && (Number.isInteger(Number(key)))) // key is an index return obj.data[key] else return obj[key] }, set: (obj, key, value) => { if (typeof(key) === 'string' && (Number.isInteger(Number(key)))) // key is an index return obj.data[key] = value else return obj[key] = value } }) } } var foo = new Foo([]) foo.data = [0, 0, 0] foo[0] = 1 console.log(foo[0]) // 1 console.log(foo.data) // [1, 0, 0]
fonte