Как бы вы перегрузили оператор [] в javascript
Я не могу найти способ перегрузить оператор [] в javascript. Кто-нибудь там знает?
Я думал о строках ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
или я не смотрю на правильные вещи.
8 ответов:
вы не можете перегружать операторы в JavaScript.
Он был предлагается для ECMAScript 4 но отверг.
Я не думаю, что вы увидите это в ближайшее время.
простой ответ заключается в том, что JavaScript позволяет получить доступ к дочерним объектам через квадратные скобки.
таким образом, вы можете определить свой класс:
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; };
вы сможете получить доступ к членам на любых экземплярах вашего класса с любым синтаксисом.
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
поскольку оператор скобок на самом деле является оператором доступа к свойствам, вы можете подключить его с помощью геттеров и сеттеров. Для IE вам придется использовать объект.defineProperty() вместо этого. Пример:
var obj = { get attr() { alert("Getter called!"); return 1; }, set attr(value) { alert("Setter called!"); return value; } }; obj.attr = 123;
то же самое для IE8+:
Object.defineProperty("attr", { get: function() { alert("Getter called!"); return 1; }, set: function(value) { alert("Setter called!"); return value; } });
для IE5-7 есть
onpropertychange
только событие, которое работает для элементов DOM, но не для других объектов.недостатком метода является то, что вы можете подключать только запросы к предопределенному набору свойств, а не к произвольному свойству без любое предопределенное имя.
Итак, вы надеетесь сделать что-то вроде var whatever = MyClassInstance[4]; ? Если это так, простой ответ заключается в том, что Javascript в настоящее время не поддерживает перегрузку операторов.
Использовать прокси. Упоминалось в других ответов, но я думаю, что это лучший пример:
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.
вам нужно использовать прокси, как описано, но в конечном итоге он может быть интегрирован в класс конструктор
return new Proxy(this, { set: function( target, name, value ) { ...}};
С 'этим'. Затем будут запущены функции set и get (также deleteProperty). Хотя вы получаете прокси-объект, который кажется другим, он по большей части работает, чтобы спросить compare ( target.конструктор === MyClass в ) это тип класса и т. д. [хотя это функция, где target.constructor.name это имя класса в тексте (просто отметив пример вещи немного разные.)]
один хитрый способ сделать это-расширить сам язык.
Шаг 1
определите пользовательское соглашение об индексировании, назовем его" []".
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));
Шаг 2
определите новую реализацию eval. (не делайте это таким образом, но это доказательство концепции).
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]");
выше не будет работать для более сложных индексов, но это может быть с сильной разбора.
альтернатива:
вместо того, чтобы прибегать к создавая свой собственный язык надмножества, вы можете вместо этого скомпилировать свою нотацию на существующий язык, а затем оценить его. Это уменьшает накладные расходы на синтаксический анализ до собственного после первого использования.
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));