在JavaScript中重载算术运算符?
考虑到JavaScript类的定义,这是我能想到的最好的措辞:在JavaScript中重载算术运算符?,javascript,operator-overloading,Javascript,Operator Overloading,考虑到JavaScript类的定义,这是我能想到的最好的措辞: var Quota = function(hours, minutes, seconds){ if (arguments.length === 3) { this.hours = hours; this.minutes = minutes; this.seconds = seconds; this.totalMilliseconds = Math.floor(
var Quota = function(hours, minutes, seconds){
if (arguments.length === 3) {
this.hours = hours;
this.minutes = minutes;
this.seconds = seconds;
this.totalMilliseconds = Math.floor((hours * 3600000)) + Math.floor((minutes * 60000)) + Math.floor((seconds * 1000));
}
else if (arguments.length === 1) {
this.totalMilliseconds = hours;
this.hours = Math.floor(this.totalMilliseconds / 3600000);
this.minutes = Math.floor((this.totalMilliseconds % 3600000) / 60000);
this.seconds = Math.floor(((this.totalMilliseconds % 3600000) % 60000) / 1000);
}
this.padL = function(val){
return (val.toString().length === 1) ? "0" + val : val;
};
this.toString = function(){
return this.padL(this.hours) + ":" + this.padL(this.minutes) + ":" + this.padL(this.seconds);
};
this.valueOf = function(){
return this.totalMilliseconds;
};
};
以及以下测试设置代码:
var q1 = new Quota(23, 58, 50);
var q2 = new Quota(0, 1, 0);
var q3 = new Quota(0, 0, 10);
console.log("Quota 01 is " + q1.toString()); // Prints "Quota 01 is 23:58:50"
console.log("Quota 02 is " + q2.toString()); // Prints "Quota 02 is 00:01:00"
console.log("Quota 03 is " + q3.toString()); // Prints "Quota 03 is 00:00:10"
是否有任何方法可以使用加法运算符隐式创建q4作为配额对象,如下所示
var q4 = q1 + q2 + q3;
console.log("Quota 04 is " + q4.toString()); // Prints "Quota 04 is 86400000"
而不是诉诸于
var q4 = new Quota(q1 + q2 + q3);
console.log("Quota 04 is " + q4.toString()); // Prints "Quota 04 is 24:00:00"
如果没有,那么在这方面,对于通过算术运算符组合自定义数字JavaScript对象,有什么最佳实践建议?不幸的是,没有
对于回退,如果您安排了返回值,则可以使用方法链接
var q4 = q1.plus(p2).plus(q3);
第二项建议:
var q4 = Quota.add(q1, q2, q3);
据我所知,Javascript(至少现在的Javascript)不支持运算符重载 我所能建议的最好方法是使用类方法从其他几个对象中创建新的配额对象。这里有一个简单的例子来说明我的意思:
// define an example "class"
var NumClass = function(value){
this.value = value;
}
NumClass.prototype.toInteger = function(){
return this.value;
}
// Add a static method that creates a new object from several others
NumClass.createFromObjects = function(){
var newValue = 0;
for (var i=0; i<arguments.length; i++){
newValue += arguments[i].toInteger();
}
return new this(newValue)
}
我不知道为什么人们继续毫无保留地回答这个问题 绝对有一种方法,我将用一个非常非常非常小的脚本概述,你不必是约翰·雷西格就能理解 在此之前,我还要声明,在JavaScript中,构造函数的工作方式是检查数组或迭代“参数”文本 e、 g.在我的“类”的构造函数中,我将迭代这些片段,确定底层片段的类型并智能地处理它 这意味着,如果您传递了一个数组,我将迭代数组以找到一个数组,然后根据数组中元素的类型迭代数组以进行进一步的处理 例如->新的someClass[instanceA,instanceB,instanceC] 然而,你们正在寻找一种更为C风格的方法来处理运算符重载,这实际上是可以实现的,这与大众的信念相反 下面是我使用MooTools创建的一个类,它支持操作符重载。在普通的旧JavaScript中,您只需使用相同的toString方法,只需将其直接附加到实例的原型 我展示这种方法的主要原因是因为我不断阅读的文本指出这种功能无法模仿。没有什么是不可能的,只有足够的困难,我将在下面展示
//////
debugger;
//Make a counter to prove I am overloading operators
var counter = 0;
//A test class with a overriden operator
var TestClass = new Class({
Implements: [Options, Events],
stringValue: 'test',
intValue: 0,
initialize: function (options) {
if (options && options instanceof TestClass) {
//Copy or compose
this.intValue += options.intValue;
this.stringValue += options.stringValue;
} else {
this.intValue = counter++;
}
},
toString: function () {
debugger;
//Make a reference to myself
var self = this;
//Determine the logic which will handle overloads for like instances
if (self instanceof TestClass) return self.intValue;
//If this is not a like instance or we do not want to overload return the string value or a default.
return self.stringValue;
}
});
//Export the class
window.TestClass = TestClass;
//make an instance
var myTest = new TestClass();
//make another instance
var other = new TestClass();
//Make a value which is composed of the two utilizing the operator overload
var composed = myTest + other;
//Make a value which is composed of a string and a single value
var stringTest = '' + myTest;
//////
在XDate的文档页面上可以看到该术语的最新显示:
在这种情况下,我相信它实际上更容易,他可以用Date对象的原型来实现同样的目标
尽管如此,我给出的方法作为一个例子,应该为其他人描述这种利用方式
编辑:
我在这里有一个完整的实现:
和其他好东西一起。我最近发现了这篇文章:
它描述了如何在对象上重新定义valueOf方法,以执行javascript中的运算符重载之类的操作。似乎您只能对正在操作的对象执行mutator操作,因此它不会执行您想要的操作。尽管如此,这还是很有趣。因为每个人都否决了我的另一个答案,所以我想发布概念验证代码,它实际上按照预期工作 这已经在chrome和IE中进行了测试
//Operator Overloading
var myClass = function () {
//Privates
var intValue = Number(0),
stringValue = String('');
//Publics
this.valueOf = function () {
if (this instanceof myClass) return intValue;
return stringValue;
}
this.cast = function (type, call) {
if (!type) return;
if (!call) return type.bind(this);
return call.bind(new type(this)).call(this);
}
}
//Derived class
var anotherClass = function () {
//Store the base reference
this.constructor = myClass.apply(this);
var myString = 'Test',
myInt = 1;
this.valueOf = function () {
if (this instanceof myClass) return myInt;
return myString;
}
}
//Tests
var test = new myClass(),
anotherTest = new anotherClass(),
composed = test + anotherTest,
yaComposed = test.cast(Number, function () {
return this + anotherTest
}),
yaCComposed = anotherTest.cast(Number, function () {
return this + test;
}),
t = test.cast(anotherClass, function () {
return this + anotherTest
}),
tt = anotherTest.cast(myClass, function () {
return this + test;
});
debugger;
如果有人愿意给出一个技术上的解释,为什么这还不够好,我会很高兴听到它 对于某些有限的用例,您可以使用运算符重载效果:
function MyIntyClass() {
this.valueOf = function() { return Math.random(); }
}
var a = new MyIntyClass();
var b = new MyIntyClass();
a < b
false
a + b
0.6169137847609818
[a, b].sort() // O(n^2) ?
[myClass, myClass]
function MyStringyClass() {
this.valueOf = function() { return 'abcdefg'[Math.floor(Math.random()*7)]; }
}
c = new MyStringyClass();
'Hello, ' + c + '!'
Hello, f!
以上代码在麻省理工学院许可下免费使用。YMMV.除了已经说过的:overriding.valueOf可能有助于产生非常强大的运算符重载。在概念验证库中,可以添加.NET样式的事件侦听器:
function hi() { console.log("hi") }
function stackoverflow() { console.log("stackoverflow") }
function bye() { console.log("bye") }
on(yourButton).click += hi + stackoverflow;
on(yourButton).click -= hi - bye;
核心思想是在调用on时临时替换valueOf:
const extendedValueOf = function () {
if (handlers.length >= 16) {
throw new Error("Max 16 functions can be added/removed at once using on(..) syntax");
}
handlers.push(this); // save current function
return 1 << ((handlers.length - 1) * 2); // serialize it as a number.
};
然后,可以使用处理程序数组将返回的数字反序列化回函数中。此外,还可以从最终值func1+func2-func3中提取位值,以便有效地了解添加了哪些函数以及删除了哪些函数
您可以在上查看源代码并使用
这里有完整的解释,它是针对AS3的,很难理解,因为它是ecmascript,它也适用于JS。您可以隐式地将对象转换为整数或字符串 只有当JavaScript需要数字或字符串时,才会隐式转换对象。在前一种情况下,转换分为三个步骤: 1.-调用值。如果结果是基元而不是对象,则使用它并将其转换为数字 2.-否则,请致电toString。如果结果是基元,请使用它并将其转换为数字 3.-否则,抛出一个TypeError。 步骤1的示例: 3*{valueOf:function{return 5} 如果JavaScript转换为字符串,则交换步骤1和步骤2:首先尝试toString,然后尝试valueOf
Paper.js可以做到这一点,例如通过点添加:
但它是用自己的语言实现的。我制作了一个脚本,用JavaScript实现操作符重载。这不是直截了当的 我很想工作,所以有一些怪癖。我将在项目页面的此处交叉发布警告,否则您可以在底部找到链接: 计算结果必须传递给新对象,因此,如果用户定义的对象名为point,则必须执行新的pointp1+p2+p3,而不是p1+p2+p3 仅支持+、-、*和/,不支持第五个算术运算符%。 对字符串+p1和比较p1==p2的强制将无法按预期工作。如果需要,应该为这些目的构建新函数,比如p1.val==p2.val 最后,计算答案所需的计算资源随着项的数量二次增加。因此,每个默认值在一个计算链中只允许有6个术语,尽管这可以增加。对于更长的计算链,将计算拆分,例如:新点新点P1+p2+p3+p4+p5+p6+新点P7+p8+p9+p10+p11+p12
.如果您的环境支持它,您还可以使用currying实现更漂亮的API:onetwothree@elliottcable好+聪明的思维,但尽管这对乘法来说可能没什么问题,但即使如此,我认为它在典型的程序员思维中也不能很好地沟通。我还是选一个。时间2。时间3;。在CoffeeScript中,您也可以删除一些参数:这里显示的不是运算符重载。此外,在您的示例中,toString将“0”返回给stringTest。您应该使用valueOf返回一个数字,并在此处替换更多的数字:。但这只是一个值替换,这不是运算符重载功能。即使使用您的方法,我也无法实现类Vector,当我这样做时,它将减去字段.x和.y:vectorC=vectorA-vectorB。要做到这一点,您需要运算符重载,这在ES5中是不可能的。我发现,将上述策略与function.bind结合使用,您可以控制调用哪个版本的方法,并且它确实可以工作,尽管它不如其他语言灵活。。。例如,您可以创建一个.cast函数,该函数接受一个对象并调用另一个类型的方法,并将上下文设置为给定的对象。。。。尽管如此,这与其他语言不同,但我仍然认为它可以工作:P@Jay我在我的浏览器和Node.js中尝试了这个,它抱怨类没有定义,所以它不起作用。。。。。。。。。哦,等等,我明白了:课程来自MooTools。您能用jQuery实现这一点吗?或者更好的是,没有任何库,只有JavaScript?如果派生类需要,将其传递给cast中的新类型可能会被忽略…Jay,你能展示一下这将如何与MyNumber类一起进行算术吗?举个例子吗?是否仅仅因为该类型具有单个int值就可以工作?可以在MIT许可证下免费使用?我想你不明白这个网站是怎么回事。@AranMulholland,你明白吗?目前的SE许可证一直是CC BY-SA,如果我理解正确的话,他们正计划转移到某种MIT,这不会使运营商超负荷,而是简单地委托给它最初的实现。因此,正如您所指出的,使用非常有限。看看哪种方法可以做到这一点。这里:Related:更好。我有点恼火,一种从负操作数返回负值到其模运算符的语言不支持运算符重载。在这一点上,世界上的每个人都必须将%实现为%b+b%b。您可以用一个小示例代码来解释这个技巧吗。谢谢我已经看到了示例代码,+20将20添加到成员x和y中。第2行使用提供的自定义解析器解释此代码段-这不是标准javascript。我还没有在Paper.js示例中看到对该解析器的调用。这像是一个非常聪明的评估吗?
const extendedValueOf = function () {
if (handlers.length >= 16) {
throw new Error("Max 16 functions can be added/removed at once using on(..) syntax");
}
handlers.push(this); // save current function
return 1 << ((handlers.length - 1) * 2); // serialize it as a number.
};
var point = new Point(5, 10);
var result = point + 20;
console.log(result); // {x: 25, y: 30}