Nie mogę znaleźć sposobu na przeciążenie operatora [] w javascript. Czy ktoś tam wie?
Myślałem na wzór ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
czy też nie patrzę na właściwe rzeczy.
javascript
operator-overloading
slyprid
źródło
źródło
MyClass
obiektu tablicę. Możesz skopiować klucze i wartości zmyArray
do swojegovar myObj = new MyClass()
obiektu.Odpowiedzi:
Nie możesz przeciążać operatorów w JavaScript.
Został zaproponowany dla ECMAScript 4, ale został odrzucony.
Myślę, że nie zobaczysz tego w najbliższym czasie.
źródło
Object arg1: a arg2: b arg3: c
jakObject["arg1:arg2:arg3:"](a,b,c)
. Możesz więc miećmyObject["[]"](1024)
: PMożesz to zrobić za pomocą ES6 Proxy (dostępne we wszystkich nowoczesnych przeglądarkach)
var handler = { get: function(target, name) { return "Hello, " + name; } }; var proxy = new Proxy({}, handler); console.log(proxy.world); // output: Hello, world
Sprawdź szczegóły na MDN .
źródło
target[name]
w getterze , OP pokazuje tylko przykłady[]
operatorem, przy okazji:var key = 'world';
console.log(proxy[key]);
Prosta odpowiedź jest taka, że JavaScript umożliwia dostęp do elementów potomnych Object poprzez nawiasy kwadratowe.
Możesz więc zdefiniować swoją klasę:
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; };
Będziesz wtedy mógł uzyskać dostęp do członków we wszystkich wystąpieniach swojej klasy za pomocą dowolnej składni.
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
źródło
foo['random']
którego twój kod nie jest w stanie zrobić.Użyj proxy. Wspomniano o tym w innym miejscu odpowiedzi, ale myślę, że to jest lepszy przykład:
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.
źródło
Ponieważ operator nawiasów jest w rzeczywistości operatorem dostępu do właściwości, można go podłączyć za pomocą metod pobierających i ustawiających. W przypadku IE będziesz musiał zamiast tego użyć Object.defineProperty (). Przykład:
var obj = { get attr() { alert("Getter called!"); return 1; }, set attr(value) { alert("Setter called!"); return value; } }; obj.attr = 123;
To samo dla IE8 +:
Object.defineProperty("attr", { get: function() { alert("Getter called!"); return 1; }, set: function(value) { alert("Setter called!"); return value; } });
W IE5-7 istnieje
onpropertychange
tylko zdarzenie, które działa dla elementów DOM, ale nie dla innych obiektów.Wadą tej metody jest to, że można podpiąć żądania tylko do wstępnie zdefiniowanego zestawu właściwości, a nie do dowolnej właściwości bez wcześniej zdefiniowanej nazwy.
źródło
obj['any_key'] = 123;
ale to, co widzę w Twoim kodzie, muszę zdefiniować setter / getter dla dowolnego (jeszcze nieznanego) klucza. To jest niemożliwe.Musisz użyć Proxy, jak wyjaśniono, ale ostatecznie można go zintegrować z konstruktorem klasy
return new Proxy(this, { set: function( target, name, value ) { ...}};
z tym'. Następnie uruchomione zostaną funkcje set i get (także deleteProperty). Chociaż otrzymujesz obiekt Proxy, który wydaje się inny, w większości przypadków działa on w celu zapytania porównania (target.constructor === MyClass) o typ klasy itd. [Nawet jeśli jest to funkcja, w której target.constructor.name jest nazwą klasy w tekst (wystarczy podać przykład rzeczy, które działają nieco inaczej)]
źródło
Więc masz nadzieję zrobić coś takiego jak var cokolwiek = MyClassInstance [4]; ? Jeśli tak, prostą odpowiedzią jest to, że JavaScript nie obsługuje obecnie przeciążania operatorów.
źródło
jednym z podstępnych sposobów jest rozszerzenie samego języka.
krok 1
zdefiniuj niestandardową konwencję indeksowania, nazwijmy ją „[]”.
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));
krok 2
zdefiniować nową implementację oceny. (nie rób tego w ten sposób, ale jest to dowód słuszności koncepcji).
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]");
powyższe nie zadziała dla bardziej złożonych indeksów, ale może być przy silniejszym parsowaniu.
alternatywny:
zamiast uciekać się do tworzenia własnego supersetu języka, możesz zamiast tego skompilować swoją notację do istniejącego języka, a następnie ją ewaluować. Zmniejsza to obciążenie parsowania do natywnego po pierwszym użyciu.
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));
źródło
Możemy proxy GET | ustaw metody bezpośrednio. Zainspirowany tym .
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]
źródło