我似乎找不到在javascript中重载[]运算符的方法。有人知道吗?
我正在思考......
MyClass.operator.lookup(index)
{
return myArray[index];
}
或者我没有看正确的事情。
答案 0 :(得分:70)
答案 1 :(得分:51)
您可以使用ES6代理(all现代浏览器中提供)
执行此操作var handler = {
get: function(target, name) {
return "Hello, " + name;
}
};
var proxy = new Proxy({}, handler);
console.log(proxy.world); // output: Hello, world
查看MDN上的详细信息。
答案 2 :(得分:13)
简单的答案是,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;
};
然后,您将能够使用任一语法访问类的任何实例上的成员。
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
答案 3 :(得分: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;
IE8 +也一样:
Object.defineProperty("attr", {
get: function() { alert("Getter called!"); return 1; },
set: function(value) { alert("Setter called!"); return value; }
});
对于IE5-7,只有onpropertychange
事件,它适用于DOM元素,但不适用于其他对象。
该方法的缺点是您只能将请求挂钩到预定义的属性集,而不是在没有任何预定义名称的任意属性上。
答案 4 :(得分:6)
使用代理。在答案的其他地方提到过,但我认为这是一个更好的例子:
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 :(得分:5)
所以你希望做类似的事情 var whatever = MyClassInstance [4]; ? 如果是这样,简单的答案是Javascript目前不支持运算符重载。
答案 6 :(得分:5)
您需要按照说明使用Proxy,但最终可以将其集成到类构造函数
中return new Proxy(this, {
set: function( target, name, value ) {
...}};
用'this'。然后将触发set和get(也是deleteProperty)函数。虽然你得到一个似乎不同的Proxy对象,但是大部分工作都要求比较(target.constructor === MyClass)它的类类型等[尽管它是一个函数,其中target.constructor.name是类名称文本(只是注意到一些工作略有不同的例子。)]
答案 7 :(得分:2)
定义自定义索引约定,让我们调用它," []"。
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));
答案 8 :(得分:1)
我们可以代理 get |直接设置 set 方法。受this的启发。
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]