你将如何在JavaScript中重载运算符

我似乎无法find在javascript中重载[]运算符的方式。 那里有人知道吗?

我正在考虑…

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

还是我不看正确的事情。

你不能在JavaScript中重载操作符。

它被提议用于ECMAScript 4,但被拒绝。

我不认为你会很快看到它。

您可以使用ES6代理(可在所有现代浏览器中使用)

 var handler = { get: function(target, name) { return "Hello, " + name; } }; var proxy = new Proxy({}, handler); console.log(proxy.world); // output: Hello, world 

查看MDN的详细信息。

简单的答案是,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 

由于括号运算符实际上是属性访问运算符,因此可以使用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; 

对于IE8 +也是一样的:

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

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

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

所以你希望做一些事情var无论= 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. 

你不能重载操作符,但是…

如果它是您正在编写的仅限Firefox的代码,请查看watch()

否则,看看这个寻求便携式手表的问题()。

一个偷偷摸摸的做法是通过扩展语言本身。

步骤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实现。 (不要这样做,但它是一个概念的certificate)。

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

以上将不适用于更复杂的索引,但可以更强大的parsing。

替代scheme:

而不是诉诸创造自己的超语言,你可以把你的符号编译成现有的语言,然后评估它。 这样可以在第一次使用它时将parsing开销降低到本地。

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

您需要使用代理解释,但它可以最终被集成到一个类的构造函数

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

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