如何在javascript中重载[]运算符
我似乎找不到在javascript中重载[]操作符的方法。有人知道吗 我在想如何在javascript中重载[]运算符,javascript,operator-overloading,Javascript,Operator Overloading,我似乎找不到在javascript中重载[]操作符的方法。有人知道吗 我在想 MyClass.operator.lookup(index) { return myArray[index]; } 或者说我看的东西不对。那么你希望做类似的事情 var where=MyClassInstance[4]; ? 如果是这样,简单的答案是Javascript目前不支持运算符重载。您不能在Javascript中重载运算符 但遭到拒绝 我认为你不会很快看到它。简单的答案是JavaScript允许通过
MyClass.operator.lookup(index)
{
return myArray[index];
}
或者说我看的东西不对。那么你希望做类似的事情 var where=MyClassInstance[4]; ?
如果是这样,简单的答案是Javascript目前不支持运算符重载。您不能在Javascript中重载运算符 但遭到拒绝
我认为你不会很快看到它。简单的答案是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元素,但不适用于其他对象
该方法的缺点是,您只能将请求挂接到预定义的属性集上,而不能挂接到没有任何预定义名称的任意属性上。您可以使用ES6 Proxy(在现代浏览器中提供)来实现这一点
查看详细信息。使用代理。答案中其他地方提到了这一点,但我认为这是一个更好的例子:
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.
一种偷偷摸摸的方法是扩展语言本身 第一步 定义一个自定义索引约定,我们称之为“[]” 步骤2 定义一个新的eval实现。(不要这样做,但这是概念证明) 上述方法不适用于更复杂的索引,但可以使用更强的解析 备选方案: 您可以将符号编译为现有语言,然后对其进行求值,而不是创建自己的超集语言。这减少了第一次使用本机后的解析开销
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));
如前所述,您需要使用代理,但它最终可以集成到类构造函数中 “这个”。然后,set和get(也是deleteProperty)函数将启动。虽然您得到的代理对象看起来不一样,但在大多数情况下,它可以询问比较(target.constructor===MyClass)它的类类型等[即使它是一个函数,其中target.constructor.name是文本中的类名(只需注意一个工作方式略有不同的示例)。]我们可以直接代理get | set方法。灵感来自
这可能已经在某些浏览器中使用代理是可行的,并且将在某个时候出现在所有浏览器中。然后看看jQuery如何根据您是使用[]还是.eq()返回不同的内容?您现在可以使用代理来执行此操作。尽管您可以定义包含符号的方法,但前提是您可以将其作为数组而不是“.”来访问。这就是SmallTalk如何将对象arg1:a arg2:b arg3:c映射为
对象[“arg1:arg2:arg3:”](a,b,c)
。因此您可以拥有myObject[“[]”(1024)
:p链接已断开:(出于性能方面的考虑,我绝对不推荐这样做,但这是解决此问题的唯一实际方法。也许编辑声明不可能这样做会使这成为一个很好的答案。这不是问题想要的。问题是要找到一种捕获foo['random']的方法
这是您的代码无法做到的。这里的答案是错误的,JS中的数组只是对象,其键可强制为uint32(-1)值,并且在其原型上有额外的方法。只需将您的MyClass
对象设置为数组。您可以将myArray
中的键和值复制到var myObj=new MyClass()
object.hey,我想重载{}操作符,有什么想法吗?你能演示一下你的方法吗?我假设这个解决方案应该适用于表达式中的任何键obj['any_key']=123;
但是我在你的代码中看到的是,我需要为任何键定义setter/getter(还不知道)键。这是不可能的。正1抵消负1,因为这不仅仅是IE。这可以为类函数完成吗?我正在努力自己找到它的语法。那么jQuery是如何工作的。您可以调用jQuery对象上的方法,如$('.foo').html(),或者获取第一个匹配的dom元素,如$('.foo')[0]jQuery是一个函数,您正在向$function传递一个参数我们如何使用它来创建我们自己的带有索引访问器的类?也就是说,我想使用我自己的构造函数,我不想构造代理。这不是真正的重载。您现在调用的不是对象本身的方法,而是代理的方法。@Pacerier您可以返回target[name]
在getter中,OP仅仅显示了带有[]
操作符的示例works,顺便说一句:var key='world';
console.log(proxy[key]);
可能值得一提的是,代理是ES6的一个特性,因此具有更有限的(and)。这对于重载[]在主干集合上,以便使用[]返回单个模型对象通过所有其他属性。你是扭曲的+1绝对恶心。我喜欢它。聪明通常是以这样或那样的方式。并不意味着这是一个不值得的练习,可以用足够的资源来回报。最懒惰的人是那些编写自己的编译程序和翻译程序的人,只是为了能在更熟悉的环境中工作nts,即使它们不可用。也就是说,如果它是由在该领域有更多经验的人不那么匆忙地写的,那么它就不会那么令人厌恶了。所有非平凡的解决方案在某种程度上都是令人厌恶的,我们的工作是了解折衷和应对后果。
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));
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 ) {
...}};
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]