Как бы вы перегрузили оператор [] в javascript

Я не могу найти способ перегрузить оператор [] в javascript. Кто-нибудь знает?

Я думал о строках...

MyClass.operator.lookup(index)
{
     return myArray[index];
}

или я не смотрю на правильные вещи.

Ответ 1

Вы не можете перегружать операторов в JavaScript.

Это было предложенное для ECMAScript 4, но отклонено.

Я не думаю, что вы это увидите в ближайшее время.

Ответ 2

Вы можете сделать это с ES6 Proxy (доступно во всех современных браузерах)

var handler = {
    get: function(target, name) {
        return "Hello, " + name;
    }
};
var proxy = new Proxy({}, handler);

console.log(proxy.world); // output: Hello, world

Проверьте подробности в MDN.

Ответ 3

Простой ответ заключается в том, что 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

Ответ 4

Использовать прокси. Это было упомянуто в других ответах, но я думаю, что это лучший пример:

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.

Ответ 5

В качестве оператора скобок на самом деле оператор доступа к ресурсам, вы можете подключить его с помощью геттеров и сеттеров. Для 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, но не для других объектов.

Недостатком метода является то, что вы можете обрабатывать запросы только на предопределенный набор свойств, а не на произвольное свойство без какого-либо предопределенного имени.

Ответ 6

Итак, вы надеетесь сделать что-то вроде var any = MyClassInstance [4]; ? Если да, то простой ответ заключается в том, что Javascript в настоящее время не поддерживает перегрузку оператора.

Ответ 7

Вы должны использовать Прокси, как объяснено, но в конечном итоге он может быть интегрирован в конструктор класса

return new Proxy(this, {
    set: function( target, name, value ) {
...}};

с этим. Затем сработают функции set и get (также deleteProperty). Несмотря на то, что вы получаете объект Proxy, который кажется другим, он по большей части работает с запросом сравнения (target.constructor === MyClass) на его тип класса и т.д. [Даже если это функция, где target.constructor.name - это имя класса в текст (просто отмечая пример вещей, которые работают немного по-другому.)]

Ответ 8

один подлый способ сделать это, расширив сам язык.

шаг 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]");

выше не будет работать для более сложных индексов, но это может быть при сильном разборе.

альтернатива:

вместо того, чтобы прибегать к созданию собственного языка надмножества, вместо этого вы можете скомпилировать свои обозначения на существующий язык, а затем проанализировать его. Это уменьшает служебные данные синтаксического анализа на native после первого использования.

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));

Ответ 9

Вы не можете перегружать операторов, но...

Если это код, который вы используете только для Firefox, посмотрите watch()

В противном случае посмотрите question, который ищет портативные часы().

Ответ 10

Мы можем получить прокси | установить методы напрямую. Вдохновлен этим.

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]