Dies ist der beste Weg, diese Frage zu formulieren, wenn man diese JavaScript-Definition der "Klasse" berücksichtigt:
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;
};
};
und den folgenden Test-Setup-Code:
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"
Gibt es eine Möglichkeit, mit dem Additionsoperator wie folgt implizit q4
als Quota
Objekt zu erstellen ...
var q4 = q1 + q2 + q3;
console.log("Quota 04 is " + q4.toString()); // Prints "Quota 04 is 86400000"
anstatt auf ... zurückzugreifen
var q4 = new Quota(q1 + q2 + q3);
console.log("Quota 04 is " + q4.toString()); // Prints "Quota 04 is 24:00:00"
Wenn nicht, was sind die Best-Practice-Empfehlungen in diesem Bereich, um benutzerdefinierte numerische JavaScript-Objekte über die arithmetischen Operatoren zusammensetzbar zu machen?
javascript
operator-overloading
Peter McG
quelle
quelle
Antworten:
Soweit mir bekannt ist, unterstützt Javascript (zumindest so wie es jetzt existiert) das Überladen von Operatoren nicht.
Das Beste, was ich vorschlagen kann, ist eine Klassenmethode zum Erstellen neuer Kontingentobjekte aus mehreren anderen. Hier ist ein kurzes Beispiel dafür, was ich meine:
// 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) }
und benutze es wie:
var n1 = new NumClass(1); var n2 = new NumClass(2); var n3 = new NumClass(3); var combined = NumClass.createFromObjects(n1, n2, n3);
quelle
Unglücklicherweise nicht.
Wenn Sie für Fallbacks die Rückgabewerte angeordnet haben, können Sie die Methodenverkettung verwenden
var q4 = q1.plus(p2).plus(q3);
quelle
one(two)(three)
one.times(two).times(three);
.Da alle meine andere Antwort abgelehnt haben, wollte ich einen Proof-of-Concept-Code veröffentlichen, der tatsächlich wie beabsichtigt funktioniert.
Dies wurde in Chrome und IE getestet.
//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;
Wenn jemand so freundlich wäre, eine technische Erklärung zu geben, WARUM dies nicht gut genug ist, würde ich mich freuen, es zu hören!
quelle
Zweiter Vorschlag:
var q4 = Quota.add(q1, q2, q3);
quelle
Sie können Ihre Objekte implizit in eine Ganzzahl oder eine Zeichenfolge konvertieren.
Objekte werden nur implizit konvertiert, wenn JavaScript eine Zahl oder eine Zeichenfolge erwartet. Im ersteren Fall erfolgt die Konvertierung in drei Schritten:
1.- Rufen Sie an
valueOf()
. Wenn das Ergebnis primitiv ist (kein Objekt), verwenden Sie es und konvertieren Sie es in eine Zahl.2.- Andernfalls anrufen
toString()
. Wenn das Ergebnis primitiv ist, verwenden Sie es und konvertieren Sie es in eine Zahl.3.- Andernfalls werfen Sie a
TypeError
. Beispiel für Schritt 1:Wenn JavaScript in einen String konvertiert wird, werden die Schritte 1 und 2 ausgetauscht: toString () wird zuerst versucht, valueOf () zweitens.
http://www.2ality.com/2013/04/quirk-implicit-conversion.html
quelle
Paper.js macht es zum Beispiel mit Punktaddition ( docs ):
var point = new Point(5, 10); var result = point + 20; console.log(result); // {x: 25, y: 30}
Dies geschieht jedoch mithilfe eines eigenen benutzerdefinierten Skriptparsers .
quelle
Ich bin kürzlich auf diesen Artikel gestoßen : http://www.2ality.com/2011/12/fake-operator-overloading.html .
Es wird beschrieben, wie Sie die valueOf-Methode für Objekte neu definieren können, um beispielsweise das Überladen von Operatoren in Javascript durchzuführen. Es scheint, dass Sie nur Mutator-Operationen an den Objekten ausführen können, an denen gearbeitet wird, sodass es nicht das tut, was Sie wollen. Trotzdem ist es interessant.
quelle
Ich habe ein Skript erstellt, das das Überladen von Operatoren in JavaScript ausführt. Es war nicht einfach, Arbeit zu machen, daher gibt es ein paar Macken. Ich werde die Vorbehalte hier auf der Projektseite kreuzen, andernfalls finden Sie den Link unten:
Berechnungsergebnisse müssen an ein neues Objekt übergeben werden, sodass Sie anstelle von (p1 + p2 + p3) einen neuen Punkt (p1 + p2 + p3) ausführen müssen (vorausgesetzt, Ihr benutzerdefiniertes Objekt heißt "Punkt").
Es werden nur +, -, * und / unterstützt, der fünfte arithmetische Opperator% nicht. Zwang zu Zeichenfolgen ("" + p1) und Vergleichen (p1 == p2) funktioniert nicht wie erwartet. Für diese Zwecke sollten bei Bedarf neue Funktionen erstellt werden, z. B. (p1.val == p2.val).
Schließlich steigt der Rechenaufwand für die Berechnung der Antwort quadratisch mit der Anzahl der Terme. Daher sind pro Standard nur 6 Begriffe in einer Berechnungskette zulässig (obwohl dies erhöht werden kann). Teilen Sie für längere Berechnungsketten die Berechnungen wie folgt auf: neuer Punkt (neuer Punkt (p1 + p2 + p3 + p4 + p5 + p6) + neuer Punkt (p7 + p8 + p9 + p10 + p11 + p12))
Die Github-Seite .
quelle
Ich bin mir nicht sicher, warum die Leute diese Frage weiterhin mit Nein beantworten!
Es gibt absolut einen Weg, den ich mit einem sehr sehr kleinen Skript skizzieren werde, das Sie nicht John Resig sein müssen, um zu verstehen ...
Bevor ich dies tue, werde ich auch feststellen, dass Ihr Konstruktor in JavaScript so funktioniert hätte, indem er nach Arrays gesucht oder das Literal 'Argumente' iteriert hätte.
zB würde ich in meinem Konstruktor meiner 'Klasse' die Arugments iterieren, den Typ der zugrunde liegenden Arugments bestimmen und sie intelligent verarbeiten.
Dies bedeutet, dass ich, wenn Sie ein Array übergeben würden, die Arugments iterieren würde, um ein Array zu finden, und dann das Array iterieren würde, um abhängig vom Typ des Elements im Array eine weitere Verarbeitung durchzuführen.
ZB -> new someClass ([instanceA, instanceB, instanceC])
Ihr sucht jedoch nach einem Ansatz im C-Stil zur Überlastung von Bedienern, der entgegen der populären Überzeugung tatsächlich erreicht werden kann.
Hier ist eine Klasse, die ich mit MooTools erstellt habe und die das Überladen von Operatoren berücksichtigt. In einfachem altem JavaScript würden Sie nur dieselbe toString-Methode verwenden und sie nur direkt an den Prototyp der Instanz anhängen.
Mein Hauptgrund für die Anzeige dieses Ansatzes ist der Text, den ich ständig lese und der besagt, dass diese Funktionalität "unmöglich" zu emulieren ist. Nichts ist unmöglich, nur ausreichend schwierig, und ich werde dies unten anzeigen ...
////// 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; //////
Die letzte Anzeige dieser Nomenklatur wurde auf der Dokumentationsseite von XDate beobachtet: http://arshaw.com/xdate/
In diesem Fall, glaube ich, war es sogar noch einfacher, er hätte den Prototyp des Date-Objekts verwenden können, um dasselbe zu erreichen.
Nichtsdestotrotz habe ich die Methode als Beispiel angegeben, die diesen Nutzungsstil für andere darstellen soll.
Bearbeiten:
Ich habe hier eine vollständige Implementierung:
http://netjs.codeplex.com/
Zusammen mit anderen Leckereien.
quelle
toString()
kehrt'0'
zustringTest
. Sie solltenvalueOf()
für die Rücksendung eines Nummernersatzes verwenden (mehr davon hier: adäquatgood.com /2010 / 3/… ). Dies ist jedoch nur ein Wertersatz. Dies ist keine Funktion zum Überladen von Operatoren. Selbst mit Ihrer Methode kann ich keine Klasse implementieren,Vector
die Felder subtrahieren würde,.x
und.y
wenn mir das gefällt :vectorC = vectorA - vectorB
. Dazu benötigen Sie eine Überlastung des Bedieners, die in ES5 nicht möglich ist.Zusätzlich zu dem, was bereits gesagt wurde: Das Überschreiben von .valueOf () kann zu einer recht leistungsstarken Überladung des Operators führen. In der Proof-of-Concept- Bibliothek von Fingers.js können Sie Ereignis-Listener im .NET-Stil hinzufügen:
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;
Die Kernidee besteht darin, valueOf vorübergehend zu ersetzen, wenn on () aufgerufen wird:
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. };
Die zurückgegebene Nummer kann dann mithilfe des Handler-Arrays wieder in die Funktion de-serialisiert werden. Darüber hinaus ist es möglich, Bitwerte aus dem Endwert (func1 + func2 - func3) zu extrahieren, damit Sie effektiv verstehen können, welche Funktionen hinzugefügt und welche Funktionen entfernt wurden.
Sie können die Quelle auf überprüfen Github überprüfen und hier mit der Demo spielen .
In diesem Artikel finden Sie eine vollständige Erklärung (es ist für AS3, schwierig, da es sich um ein Ecmascript handelt, das auch für JS funktioniert).
quelle
Für einige eingeschränkte Anwendungsfälle können Operator-Überladungseffekte auftreten:
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!
Der obige Code kann kostenlos unter der MIT-Lizenz verwendet werden. YMMV.
quelle