Здається, я не можу знайти спосіб перевантажити оператор [] у javascript. Хтось там знає?
Я думав про лінії ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
або я не дивлюся на правильні речі.
Здається, я не можу знайти спосіб перевантажити оператор [] у javascript. Хтось там знає?
Я думав про лінії ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
або я не дивлюся на правильні речі.
MyClass
об’єкт масивом. Ви можете скопіювати ключі та значення з myArray
вашого var myObj = new MyClass()
об’єкта.
Відповіді:
Ви не можете перевантажувати оператори в JavaScript.
Він був запропонований для ECMAScript 4, але відхилений.
Я не думаю, що ви побачите це найближчим часом.
Object arg1: a arg2: b arg3: c
як Object["arg1:arg2:arg3:"](a,b,c)
. Отже, ви можете мати myObject["[]"](1024)
: P
target[name]
в геттер, ОП лише показує приклади
[]
оператором, до речі:var key = 'world';
console.log(proxy[key]);
Проста відповідь полягає в тому, що 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
foo['random']
який ваш код не може зробити.
Використовуйте проксі. Це було згадано в інших місцях у відповідях, але я думаю, що це кращий приклад:
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.
Оскільки оператор дужок насправді є оператором доступу до властивостей, ви можете зачепити його за допомогою геттерів та сетерів. Для IE вам доведеться використовувати Object.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, але не для інших об'єктів.
Недоліком методу є те, що ви можете підключати лише запити до попередньо визначеного набору властивостей, а не довільних властивостей без будь-якого заздалегідь визначеного імені.
obj['any_key'] = 123;
але те, що я бачу у вашому коді, мені потрібно визначити setter / getter для будь-якого (ще невідомого) ключа. Це неможливо.
Вам потрібно використовувати Proxy, як пояснено, але в кінцевому підсумку його можна інтегрувати в конструктор класів
return new Proxy(this, {
set: function( target, name, value ) {
...}};
з цим'. Тоді функція set і get (також deleteProperty) спрацює. Хоча ви отримуєте об'єкт Proxy, який здається різним, здебільшого працює запитувати порівняння (target.constructor === MyClass) це тип класу тощо [хоча це функція, де target.constructor.name - це назва класу в текст (лише зазначивши приклад речей, які працюють дещо інакше.)]
Отже, ви сподіваєтесь зробити щось на зразок var whatever = MyClassInstance [4]; ? Якщо так, то проста відповідь полягає в тому, що Javascript наразі не підтримує перевантаження оператора.
один підлий спосіб зробити це шляхом розширення самої мови.
визначити власну угоду індексації, назвемо її "[]".
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));
визначити нову реалізацію 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));
Ми можемо отримати проксі | встановлювати методи безпосередньо. Натхненний цим .
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]