Je n'arrive pas à trouver le moyen de surcharger l'opérateur [] en javascript. Quelqu'un sait-il?
Je pensais aux lignes de ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
ou est-ce que je ne regarde pas les bonnes choses.
javascript
operator-overloading
slypride
la source
la source
MyClass
objet un tableau. Vous pouvez copier les clés et les valeurs demyArray
vers votrevar myObj = new MyClass()
objet.Réponses:
Vous ne pouvez pas surcharger les opérateurs dans JavaScript.
Il a été proposé pour ECMAScript 4 mais rejeté.
Je ne pense pas que vous le verrez de si tôt.
la source
Object arg1: a arg2: b arg3: c
asObject["arg1:arg2:arg3:"](a,b,c)
. Vous pouvez donc avoirmyObject["[]"](1024)
: PVous pouvez le faire avec ES6 Proxy (disponible dans tous les navigateurs modernes)
var handler = { get: function(target, name) { return "Hello, " + name; } }; var proxy = new Proxy({}, handler); console.log(proxy.world); // output: Hello, world
Vérifiez les détails sur MDN .
la source
target[name]
dans le getter, OP montre juste les exemples[]
opérateur, btw:var key = 'world';
console.log(proxy[key]);
La réponse simple est que JavaScript permet d'accéder aux enfants d'un objet via les crochets.
Vous pouvez donc définir votre 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; };
Vous pourrez alors accéder aux membres sur toutes les instances de votre classe avec l'une ou l'autre syntaxe.
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
la source
foo['random']
ce que votre code n'est pas capable de faire.Utilisez un proxy. Cela a été mentionné ailleurs dans les réponses mais je pense que c'est un meilleur exemple:
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.
la source
Comme l'opérateur de parenthèses est en fait un opérateur d'accès à la propriété, vous pouvez l'accrocher avec des getters et des setters. Pour IE, vous devrez utiliser Object.defineProperty () à la place. Exemple:
var obj = { get attr() { alert("Getter called!"); return 1; }, set attr(value) { alert("Setter called!"); return value; } }; obj.attr = 123;
Idem pour IE8 +:
Object.defineProperty("attr", { get: function() { alert("Getter called!"); return 1; }, set: function(value) { alert("Setter called!"); return value; } });
Pour IE5-7, il n'y a que l'
onpropertychange
événement, qui fonctionne pour les éléments DOM, mais pas pour les autres objets.L'inconvénient de la méthode est que vous ne pouvez accrocher que les requêtes à un ensemble de propriétés prédéfini, pas à une propriété arbitraire sans nom prédéfini.
la source
obj['any_key'] = 123;
mais ce que je vois dans votre code, j'ai besoin de définir setter / getter pour toute clé (pas encore connue). C'est impossible.Vous devez utiliser Proxy comme expliqué, mais il peut finalement être intégré dans un constructeur de classe
return new Proxy(this, { set: function( target, name, value ) { ...}};
avec ça'. Ensuite, les fonctions set et get (également deleteProperty) se déclenchent. Bien que vous obteniez un objet Proxy qui semble différent, il fonctionne pour la plupart de demander à comparer (target.constructor === MyClass) son type de classe, etc. [même si c'est une fonction où target.constructor.name est le nom de la classe dans texte (en notant simplement un exemple de choses qui fonctionnent légèrement différemment.)]
la source
Vous espérez donc faire quelque chose comme var n'importe quoi = MyClassInstance [4]; ? Si tel est le cas, la réponse simple est que Javascript ne prend actuellement pas en charge la surcharge des opérateurs.
la source
une façon sournoise de le faire est d'étendre le langage lui-même.
étape 1
définir une convention d'indexation personnalisée, appelons-la, "[]".
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));
étape 2
définir une nouvelle implémentation eval. (ne faites pas cela de cette façon, mais c'est une preuve de concept).
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]");
ce qui précède ne fonctionnera pas pour des index plus complexes, mais cela peut l'être avec une analyse plus poussée.
alternative:
au lieu de recourir à la création de votre propre langage de surensemble, vous pouvez à la place compiler votre notation dans le langage existant, puis l'évaluer. Cela réduit la surcharge d'analyse en natif après la première utilisation.
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));
la source
Nous pouvons obtenir un proxy | définir des méthodes directement. Inspiré par cela .
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]
la source