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.
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.
MyClass
objet un tableau. Vous pouvez copier les clés et les valeurs de myArray
vers votre var 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.
Object arg1: a arg2: b arg3: c
as Object["arg1:arg2:arg3:"](a,b,c)
. Vous pouvez donc avoir myObject["[]"](1024)
: P
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
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.
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.
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.)]
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.
une façon sournoise de le faire est d'étendre le langage lui-même.
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));
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.
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));
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]