在JavaScript中重载算术运算符?
考虑到这个JavaScript的“类”定义,这是我能想到的最好的方法:
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; }; };
和以下testing设置代码:
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"
有没有什么办法使用加法运算符隐式创buildq4
作为Quota
对象,如下所示…
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"
如果没有什么是这方面的最佳做法build议,使自定义的数字JavaScript对象可以通过算术运算符组合?
据我所知,JavaScript(至less现在存在)不支持运算符重载。
我可以build议的最好的方法是从其他几个人制作新的配额对象。 下面是我的意思的一个简单例子:
// 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) }
并使用它像:
var n1 = new NumClass(1); var n2 = new NumClass(2); var n3 = new NumClass(3); var combined = NumClass.createFromObjects(n1, n2, n3);
很不幸的是,不行。
对于回退,如果你安排了返回值,你可以使用方法链
var q4 = q1.plus(p2).plus(q3);
由于每个人都投了我的其他答案,我想张贴概念validation码,其实际上是按照预期工作。
这已经在Chrome和IEtesting。
//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;
如果有人愿意给出一个技术性的解释为什么这不够好,我会很高兴听到!
第二个build议:
var q4 = Quota.add(q1, q2, q3);
我最近遇到这篇文章: http : //www.2ality.com/2011/12/fake-operator-overloading.html 。
它描述了如何重新定义对象上的valueOf方法,以便在JavaScript中执行类似于运算符重载的操作。 看起来你只能真正对正在操作的对象执行mutator操作,所以它不会做你想要的。 它很有趣,但是tho。
你可以隐式转换为整数或string,你的对象
如果JavaScript需要一个数字或string,则对象只能被隐式转换。 在前一种情况下,转换需要三个步骤:
1.-调用valueOf()。 如果结果是原始的(不是对象),则使用它并将其转换为数字。
2.-否则,调用toString()。 如果结果是原始的,则使用它并将其转换为数字。
3.否则,抛出一个TypeError。 步骤1的示例:
3 * {valueOf:function(){return 5}}
如果JavaScript转换为string,则交换步骤1和2:首先尝试toString(),然后再尝试valueOf()。
http://www.2ality.com/2013/04/quirk-implicit-conversion.html
我不知道为什么人们继续回答这个问题没有!
绝对有一种方法,我将用一个非常小的脚本来概述,你不需要John Resig理解…
在我这样做之前,我还会指出,在JavaScript中,构造函数的工作方式是检查数组或迭代“参数”字面值。
例如在我的“类”的构造函数中,我将遍历这些arugments,确定底层arugments的types并智能地处理它。
这意味着如果你传递了一个数组,我会遍历这些数组来find一个数组,然后迭代这个数组来进行进一步处理,这取决于数组中的元素的types。
例如 – > new someClass([instanceA,instanceB,instanceC])
然而,你们正在寻求一种更“C”式的操作符重载方式,这种方式实际上可能与人们的信仰相反。
这是我用MooTools创build的一个类,它承认运算符重载。 在普通的旧JavaScript中,您只需要使用相同的toString方法直接将其附加到实例的原型。
我显示这种方法的主要原因是由于我不断阅读的文本说明这个function是“不可能”模拟的。 没有什么是不可能的,只有足够的困难,我会显示下面…
////// 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的文档页面上可以看到这个术语的最新显示: http : //arshaw.com/xdate/
在这种情况下,我相信它实际上更为经济,他可以使用Date对象的原型来达到相同效果。
我所提供的方法也不应该把这种利用方式描述为他人。
编辑:
我在这里有一个完整的实现:
随着其他好东西。
我做了一个脚本,在JavaScript中操作符重载。 工作并不是直截了当,所以有一些怪癖。 我会在项目页面上发布警告,否则你可以在底部find链接:
-
计算结果必须传递给一个新的对象,所以不用(p1 + p2 + p3),你必须做新的点(p1 + p2 + p3),(假设你的用户定义的对象被命名为“point”)。
-
只有+, – ,*和/被支持,第五个算术操作符%不是。 强制转换为string(“”+ p1)和比较(p1 == p2)将无法按预期工作。 如果需要,应该为这些目的构build新的函数,如(p1.val == p2.val)。
-
最后,计算答案所需的计算资源随着项数的增加而二次增加。 因此,一个计算链中只允许使用6个术语(尽pipe这可以增加)。 对于比这更长的计算链,将计算分开,例如:新点(新点(p1 + p2 + p3 + p4 + p5 + p6)+新点(p7 + p8 + p9 + p10 + p11 + p12))
Github页面 。
除了已经说过的话:覆盖.valueOf()可能有助于产生相当强大的运算符重载。 在概念validationFingers.js库中,您可以添加.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()被调用时暂时replacevalueOf:
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)中提取位值,这样可以有效地理解添加的函数以及删除了哪些函数。
你可以在github上查看源代码,并在这里玩demo 。
在这篇文章中有完整的解释(这是AS3的,因为它的ecmascript它会为JS工作)。
对于一些有限的用例,你可以让操作符“重载”效果:
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!
上述代码可以在MIT许可下自由使用。 因人而异。
Paper.js做到这一点,例如增加点( 文档 ):
var point = new Point(5, 10); var result = point + 20; console.log(result); // {x: 25, y: 30}
但它使用自己的自定义脚本parsing器 。