Vraag Hoe zou u de operator [] overbelasten in javascript


Ik kan de weg niet vinden om de operator [] te overbelasten in javascript. Weet iemand daar?

Ik dacht in de trant van ...

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

of kijk ik niet naar de juiste dingen.


62
2017-11-10 21:31


oorsprong


antwoorden:


U kunt operators niet overbelasten in JavaScript.

Het was voorgesteld voor ECMAScript 4 maar afgewezen.

Ik denk niet dat je het snel zult zien.


64
2017-11-10 21:37



U kunt dit doen met ES6 Proxy (beschikbaar in alle moderne browsers)

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

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

Bekijk details op MDN.


43
2017-09-04 06:50



Het eenvoudige antwoord is dat JavaScript via de vierkante haken toegang biedt tot kinderen van een object.

Dus je zou je klas kunnen definiëren:

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

Je hebt dan toegang tot de leden in alle instanties van je klas met beide syntaxis.

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

13
2018-04-19 22:28



Omdat de operator van de brackets eigenlijk de operator voor eigendomsrechten is, kunt u deze vastmaken met getters en setters. Voor IE moet u Object.defineProperty () gebruiken. Voorbeeld:

var obj = {
    get attr() { alert("Getter called!"); return 1; },
    set attr(value) { alert("Setter called!"); return value; }
};

obj.attr = 123;

Hetzelfde voor IE8 +:

Object.defineProperty("attr", {
    get: function() { alert("Getter called!"); return 1; },
    set: function(value) { alert("Setter called!"); return value; }
});

Voor IE5-7 is dat zo onpropertychange alleen een gebeurtenis, die werkt voor DOM-elementen, maar niet voor andere objecten.

Het nadeel van de methode is dat u alleen kunt inhaken op verzoeken naar vooraf gedefinieerde set eigenschappen, niet op willekeurige eigenschappen zonder een vooraf gedefinieerde naam.


6
2017-08-21 19:12



Dus je hoopt zoiets te doen var whatever = MyClassInstance [4]; ? Als dat het geval is, is een eenvoudig antwoord dat JavaScript momenteel geen overbelasting door de operator ondersteunt.


5
2017-11-10 21:35



Gebruik een proxy. Het werd elders in de antwoorden genoemd, maar ik denk dat dit een beter voorbeeld is:

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
2018-05-05 18:45



U moet Proxy gebruiken zoals uitgelegd, maar het kan uiteindelijk in een klasse worden geïntegreerd bouwer 

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

hiermee'. Vervolgens worden de functies set en get (ook deleteProperty) geactiveerd. Hoewel je een proxy-object ziet dat anders lijkt, werkt het voor het grootste deel om de vergelijking (target.constructor === MyClass), het klassetype enz. [Hoewel het een functie is waarbij target.constructor.name de klassenaam is in tekst (alleen een voorbeeld van dingen die enigszins van elkaar verschillen.)]


3
2017-09-27 03:12



een stiekeme manier om dit te doen is door de taal zelf uit te breiden.

stap 1

een aangepaste indexeringsconventie definiëren, laten we het '[]' noemen.

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

stap 2

een nieuwe eval-implementatie definiëren. (doe dit niet op deze manier, maar het is een proof of 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]");

het bovenstaande werkt niet voor complexere indices, maar het kan met een sterkere parsering.

alternatief:

in plaats van je toevlucht te nemen tot het creëren van je eigen superset-taal, kun je in plaats daarvan je notatie naar de bestaande taal compileren en deze dan evalueren. Dit vermindert de parseer-overhead naar native na de eerste keer dat u het gebruikt.

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

1
2017-07-24 12:51