我似乎找不到在JavaScript中重载[]
运算符的方法。有没有人知道如何做?
我正在考虑...
MyClass.operator.lookup(index)
{
return myArray[index];
}
还是我没有看对地方。
我似乎找不到在JavaScript中重载[]
运算符的方法。有没有人知道如何做?
我正在考虑...
MyClass.operator.lookup(index)
{
return myArray[index];
}
还是我没有看对地方。
[]
操作符,如下:var key = 'world';
console.log(proxy[key]);
- Klesunproxy[123]
或 proxy[new Date()]
中检查 typeof name
,您会发现它们都被 强制转换为字符串。 - Beni Cherniavsky-PaskinObject arg1: a arg2: b arg3: c
映射为Object["arg1:arg2:arg3:"](a,b,c)
。所以你可以有myObject["[]"](1024)
:P - DmytroMyClass = 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
foo['random']
,而你的代码无法做到。 - Pacerier我们可以直接代理get|set方法。灵感来自这里。
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]
使用代理。答案中已经提到了它,但我认为这是一个更好的例子:
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.
var obj = {
get attr() { alert("Getter called!"); return 1; },
set attr(value) { alert("Setter called!"); return value; }
};
obj.attr = 123;
Object.defineProperty("attr", {
get: function() { alert("Getter called!"); return 1; },
set: function(value) { alert("Setter called!"); return value; }
});
对于IE5-7,只有onpropertychange
事件可用于DOM元素,而不能用于其他对象。
这种方法的缺点是您只能钩住预定义属性集的请求,而无法钩住任意没有预定义名称的属性。
obj['any_key'] = 123;
中的任何键,但是根据您的代码,我需要为任何(尚未知道)键定义 setter/getter。这是不可能的。 - dma_kvar a = new Array(2);
function trap_indexing(obj,index) {
Object.defineProperty(obj,index,{
get() {
console.log("getting");
return this['_shadow'+index];
},
set(p) {
console.log("setting");
this['_shadow'+index] = p;
}
});
}
trap_indexing(a,0);
trap_indexing(a,1);
trap_indexing(a,2);
a[0] = 'barf';
console.log(a[0]);
a[1] = 'cat';
console.log(a[1]);
- mondaugen有一个聪明的方法是通过扩展语言本身来实现这一点。
定义一个自定义索引约定,让我们称之为“[]”。
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));
您需要按照说明使用代理,但最终可以将其集成到类的构造函数中。
return new Proxy(this, {
set: function( target, name, value ) {
...}};
使用“this”。然后,set和get(还有deleteProperty)函数将触发。虽然您获得了一个看起来不同的代理对象,但它大部分工作都是询问比较(target.constructor === MyClass)它的类类型等。[即使它是一个函数,其中target.constructor.name是文本中的类名(只是注意一些略微不同的工作示例。)]
所以您希望做类似于 var whatever = MyClassInstance[4]; 的操作吗?如果是这样,简单的答案是Javascript目前不支持运算符重载。
看看Symbol.iterator。您可以实现用户定义的@@iterator方法使任何对象可迭代。
众所周知,Symbol.iterator符号指定对象的默认迭代器。由for...of使用。
class MyClass {
constructor () {
this._array = [data]
}
*[Symbol.iterator] () {
for (let i=0, n=this._array.length; i<n; i++) {
yield this._array[i]
}
}
}
const c = new MyClass()
for (const element of [...c]) {
// do something with element
}
MyClass
对象变成一个数组即可。您可以将myArray
中的键和值复制到您的var myObj = new MyClass()
对象中。 - jpaugh