你会如何在javascript中重载[]运算符

sly*_*rid 74 javascript operator-overloading

我似乎无法找到在javascript中重载[]运算符的方法.有人知道吗?

我在想......

MyClass.operator.lookup(index)
{
     return myArray[index];
}
Run Code Online (Sandbox Code Playgroud)

或者我不是在看正确的事情.

Pet*_*ley 73

您不能在JavaScript中重载运算符.

它被提议用于ECMAScript 4但被拒绝.

我认为你很快就会看到它.

  • 对于某些浏览器中的代理,这可能是可行的,并且将在某些时候出现在所有浏览器中.请参阅https://github.com/DavidBruant/ProxyArray (4认同)
  • 链接已失效:( (3认同)
  • @Tristan链接坏了 (2认同)
  • 您现在可以使用代理进行操作。 (2认同)

ave*_*Joe 55

您可以使用ES6代理执行此操作(适用于所有现代浏览器)

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

console.log(proxy.world); // output: Hello, world
Run Code Online (Sandbox Code Playgroud)

检查MDN的详细信息.

  • 我们将如何使用它来创建我们自己的带有索引访问器的类?即我想使用我自己的构造函数,我不想构造一个代理。 (3认同)
  • 这不是真正的超载。现在,您不再调用对象本身的方法,而是调用代理的方法。 (3认同)
  • 也适用于 `[]` 运算符,顺便说一句:`var key = 'world';` `console.log(proxy[key]);` (2认同)

Bra*_*ney 15

简单的答案是JavaScript允许通过方括号访问Object的子级.

所以你可以定义你的类:

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;
};
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用任一语法访问类的任何实例上的成员.

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
Run Code Online (Sandbox Code Playgroud)

  • +100,非常有用,-100对于Milmetric的评论 (13认同)
  • 这**不是**问题想要的.问题是要求一种方法来捕获你的代码无法做到的`foo ['random']`. (3认同)
  • 由于性能原因,我绝对不建议这样做,但这是此处唯一实际的解决方案。可能的编辑指出不可能,这将是一个很好的答案。 (2认同)

Eya*_*yal 8

使用代理.在答案的其他地方提到过,但我认为这是一个更好的例子:

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.
Run Code Online (Sandbox Code Playgroud)


kst*_*tep 7

由于括号运算符实际上是属性访问运算符,因此可以使用getter和setter挂钩它.对于IE,您将不得不使用Object.defineProperty().例:

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

obj.attr = 123;
Run Code Online (Sandbox Code Playgroud)

IE8 +也一样:

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

对于IE5-7,onpropertychange只有事件,它适用于DOM元素,但不适用于其他对象.

该方法的缺点是您只能将请求挂钩到预定义的属性集,而不是在没有任何预定义名称的任意属性上.

  • 加1来抵消负1,因为这不仅仅是IE. (3认同)

Jab*_*ber 7

我们可以代理get | 直接设置方法。灵感来自

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]
Run Code Online (Sandbox Code Playgroud)


Mat*_*nar 5

所以你希望做一些像var what = MyClassInstance [4]; ?如果是这样,简单的答案是Javascript目前不支持运算符重载.

  • jQuery 是一个函数,您将一个参数传递给 $ 函数。因此 () 括号,而不是 [] (2认同)

Dmi*_*try 5

一种偷偷摸摸的方法是扩展语言本身。

步骤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));
Run Code Online (Sandbox Code Playgroud)

第2步

定义一个新的评估实现。(不要这样做,但这是概念的证明)。

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]");
Run Code Online (Sandbox Code Playgroud)

上面的方法不适用于更复杂的索引,但是可以使用更强大的解析功能。

替代方案:

不必诉诸于创建自己的超集语言,而是可以将符号编译为现有语言,然后进行评估。第一次使用后,这会将解析开销减少到本机。

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));
Run Code Online (Sandbox Code Playgroud)

  • 你是歪的 +1 (4认同)
  • 绝对恶心。我喜欢它。 (2认同)

Mas*_*mes 5

您需要按照说明使用Proxy,但最终可以将其集成到类构造函数中

return new Proxy(this, {
    set: function( target, name, value ) {
...}};
Run Code Online (Sandbox Code Playgroud)

有了这个'.然后将触发set和get(也是deleteProperty)函数.虽然你得到一个代理对象,这似乎不同它的大部分工作要求比较(target.constructor === MyClass的),它的类的类型等,即使它是一个函数,其中target.constructor.name是在类名文本(只是注意到一些工作略有不同的例子.)]