Перегрузка арифметических операторов в 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;
};
};
и следующий код установки теста:
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 как 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"
если нет, то каковы рекомендации по лучшей практике в этой области для создания пользовательского числового JavaScript объекты, составляемые с помощью арифметических операторов?
11 ответов:
насколько мне известно, 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) }и использовать его как:
var n1 = new NumClass(1); var n2 = new NumClass(2); var n3 = new NumClass(3); var combined = NumClass.createFromObjects(n1, n2, n3);
к сожалению, нет.
для резервных версий, если вы расположили возвращаемые значения, вы можете использовать метод chaining
var q4 = q1.plus(p2).plus(q3);
поскольку все проголосовали за мой другой ответ, я хотел опубликовать доказательство кода концепции, который на самом деле работает по назначению.
Это было протестировано в 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;Если кто-то будет так добр, чтобы дать техническое объяснение, почему это не достаточно хорошо, я буду рад услышать его!
недавно я наткнулся на эту статью:http://www.2ality.com/2011/12/fake-operator-overloading.html .
Он описывает, как вы можете переопределить метод valueOf для объектов, чтобы сделать что-то вроде перегрузки оператора в javascript. Похоже, что вы можете действительно выполнять операции мутатора только на объектах, с которыми работаете, поэтому он не будет делать то, что вы хотите. Его интересно тем не менее Тхо.
вы можете неявно преобразовать в целое число или строку, ваши объекты
объекты только неявно преобразуются, если JavaScript ожидает число или строку. В первом случае преобразование выполняется в три этапа:
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
бумаги.js делает это, например, с добавлением точки ( docs):
var point = new Point(5, 10); var result = point + 20; console.log(result); // {x: 25, y: 30}но он делает это, используя свой собственный пользовательский скрипт парсера.
Я не уверен, почему люди продолжают ответа на этот вопрос нет!
есть абсолютно способ, который я опишу с очень маленьким сценарием, который вам не нужно Быть Джоном отставкой, чтобы понять...
прежде чем я это сделаю, я также скажу, что в JavaScript способ, которым работал бы ваш конструктор, заключается в проверке массивов или повторении литерала "аргументы".
например, в моем конструкторе моего "класса" я бы повторил arugments, определить тип лежащих в основе рукколы и обрабатывать его разумно.
это означает, что если вы передали массив, я бы повторил arugments, чтобы найти массив, а затем повторил массив для дальнейшей обработки в зависимости от типа элемента в массиве.
например - > new someClass([ instanceA, instanceB, instanceC])
однако вы, ребята, ищете более" C " подход к перегрузке оператора, который на самом деле может быть достигнут вопреки populare вера.
вот класс,который я создал с помощью MooTools, который делает перегрузку оператора honor. В обычном старом 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: http://arshaw.com/xdate/
в этом случае я считаю, что на самом деле это было еще проще, он мог бы использовать прототип объекта даты для достижения того же самого.
тем не менее метод, который я привел в качестве примера, который должен изображать этот стиль использования для других.
Edit:
У меня есть полное реализация здесь:
вместе с другими вкусностями.
В дополнение к тому, что уже было сказано: переопределение .valueOf () может помочь произвести довольно мощную перегрузку оператора. В доказательств -- принципиальной схемы пальцы.js lib вы можете добавить прослушиватели событий в стиле .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;основная идея заключается в замене временно valueOf при вызове on ():
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 и играть с демо здесь.
полное объяснение существует в этом статьи (это для AS3, жестко, так как это ecmascript, он будет работать и для JS).
Я сделал скрипт, который делает перегрузку оператора в JavaScript. Это не было прямо вперед, чтобы сделать работу, так что есть несколько причуд, хотя. Я пересеку публикацию предостережений здесь со страницы проекта, в противном случае вы можете найти ссылку внизу:
результаты расчета должны быть переданы в новый объект, поэтому вместо (p1 + p2 + p3) вы должны сделать новую точку(p1 + p2 + p3), (учитывая, что ваш пользовательский объект называется "точка").
только +, - , * и / поддерживаются, пятый арифметический опператор % не является. Приведение к строкам (""+p1) и сравнения (p1 == p2) не будет работать, как ожидалось. Новые функции должны быть построены для этих целей, если это необходимо, как (П1.val = = p2.вал.)
наконец, вычислительные ресурсы, необходимые для вычисления ответа, увеличиваются квадратично с числом членов. Поэтому в одной цепочке вычислений по умолчанию допускается только 6 терминов (хотя это может быть увеличено). Надолго вычислительные цепочки, чем это, разделите вычисления, например: новая точка(новая точка(p1 + p2 + p3 + p4 + p5 + p6) + новая точка (p7 + p8 + p9 + p10 + p11 + p12))
The страница Github.
для некоторых ограниченных случаев использования вы можете иметь эффекты "перегрузки" оператора:
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. МММ.
Comments