Domanda

Questo è il modo migliore in cui posso pensare di formulare questa domanda, dato questo JavaScript "classe" Definizione:

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;
    };
};

e il seguente codice di configurazione del test:

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"

Esiste un modo per creare implicitamente q4 come oggetto Quota usando l'operatore addizione come segue ...

var q4 = q1 + q2 + q3;
console.log("Quota 04 is " + q4.toString());    // Prints "Quota 04 is 86400000"

piuttosto che ricorrere a ...

var q4 = new Quota(q1 + q2 + q3);
console.log("Quota 04 is " + q4.toString());    // Prints "Quota 04 is 24:00:00"

In caso contrario, quali sono le raccomandazioni delle migliori pratiche in quest'area per rendere componibili oggetti JavaScript numerici personalizzati tramite gli operatori aritmetici?

È stato utile?

Soluzione

Per quanto ne so, Javascript (almeno come esiste ora) non supporta il sovraccarico dell'operatore.

Il meglio che posso suggerire è un metodo di classe per creare nuovi oggetti quota da molti altri. Ecco un breve esempio di cosa intendo:

// 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)
}

e usalo come:

var n1 = new NumClass(1);
var n2 = new NumClass(2);
var n3 = new NumClass(3);

var combined = NumClass.createFromObjects(n1, n2, n3);

Altri suggerimenti

Purtroppo no.

Per i fallback, se hai organizzato i valori di ritorno, puoi usare il concatenamento dei metodi

var q4 = q1.plus(p2).plus(q3);

Dato che tutti hanno votato la mia altra risposta, ho voluto pubblicare un codice di prova del concetto che in effetti funziona come previsto.

Questo è stato testato in Chrome e 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;

Se qualcuno fosse così gentile da dare una spiegazione tecnica PERCHÉ questo non è abbastanza buono sarei felice di ascoltarlo!

Secondo suggerimento:

var q4 = Quota.add(q1, q2, q3);

Di recente ho trovato questo articolo: http: //www.2ality .com / 2011/12 / fake-operator-overloading.html .

Descrive come è possibile ridefinire il metodo valueOf sugli oggetti per fare qualcosa come il sovraccarico dell'operatore in javascript. Sembra che tu possa davvero eseguire operazioni di mutatore solo sugli oggetti su cui si opera, quindi non farebbe quello che vuoi. È comunque interessante.

puoi implicitamente convertire in numero intero o stringa, i tuoi oggetti

Gli oggetti vengono convertiti in modo implicito solo se JavaScript prevede un numero o una stringa. Nel primo caso, la conversione prevede tre passaggi:

1.- Chiama valueOf (). Se il risultato è primitivo (non un oggetto), usalo e convertilo in un numero.

2.- Altrimenti, chiama toString (). Se il risultato è primitivo, usalo e convertilo in un numero.

3.- Altrimenti, lancia un TypeError. Esempio per il passaggio 1:

  

3 * {valueOf: function () {return 5}}

Se JavaScript viene convertito in stringa, i passaggi 1 e 2 vengono scambiati: toString () viene provato per primo, valueOf () secondo.

http://www.2ality.com/2013/04/ capriccio-implicita-conversion.html

Paper.js lo fa, ad esempio con l'aggiunta di punti ( docs ):

var point = new Point(5, 10);
var result = point + 20;
console.log(result); // {x: 25, y: 30}

Ma lo fa usando il proprio parser .

Non sono sicuro del motivo per cui le persone continuano a rispondere a questa domanda senza!

C'è assolutamente un modo che tratterò con una sceneggiatura molto piccola che il tuo non deve essere John Resig per capire ...

Prima di farlo, dichiarerò anche che in JavaScript il modo in cui il tuo costruttore avrebbe funzionato è controllando gli array o ripetendo letteralmente gli 'argomenti'.

es. Nel mio costruttore della mia "classe" avrei ripetuto gli arugment, determinato il tipo di arugment sottostanti ed elaborato in modo intelligente.

Ciò significa che se avessi passato un array avrei ripetuto gli arugment per trovare un array e quindi avrei ripetuto l'array per eseguire ulteriori elaborazioni a seconda del tipo dell'elemento nell'array.

es. - > new someClass ([istanzaA, istanzaB, istanzaC])

Comunque voi ragazzi state cercando un altro "C" approccio di stile al sovraccarico dell'operatore che può essere effettivamente ottenuto in contrasto con la credenza popolare.

Ecco una classe che ho creato usando MooTools che onora il sovraccarico dell'operatore. Nel semplice vecchio JavaScript useresti semplicemente lo stesso metodo toString per collegarlo direttamente al prototipo dell'istanza.

Il mio motivo principale per visualizzare questo approccio è a causa del testo che leggo continuamente che afferma che questa funzionalità è "impossibile". emulare. Niente è impossibile solo sufficientemente difficile e lo mostrerò di seguito ...

 //////

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;

//////

La visualizzazione più recente di questa nomenclatura è stata osservata nella pagina della documentazione di XDate: http://arshaw.com/xdate/

In questo caso credo che in realtà fosse ancora più semplice, avrebbe potuto usare il prototipo dell'oggetto Date per ottenere lo stesso.

Nondimeno il metodo che ho fornito come esempio che dovrebbe rappresentare questo stile di utilizzo per gli altri.

Modifica:

Ho un'implementazione completa qui:

http://netjs.codeplex.com/

Insieme ad altre chicche.

Ho creato uno script che sovraccarica l'operatore in JavaScript. Non è stato semplice lavorare, quindi ci sono alcune stranezze. Inserirò qui le avvertenze dalla pagina del progetto, altrimenti puoi trovare il link in basso:

  • I risultati del calcolo devono essere passati a un nuovo oggetto, quindi invece di (p1 + p2 + p3) devi fare un nuovo punto (p1 + p2 + p3), (dato che il tuo oggetto definito dall'utente è chiamato " punto ".)

  • Sono supportati solo +, -, * e /, il quinto opperatore aritmetico% non lo è. La coercizione a stringhe (" " + p1) e confronti (p1 == p2) non funzioneranno come previsto. Nuove funzioni dovrebbero essere create per questi scopi se necessario, come (p1.val == p2.val).

  • Infine, le risorse computazionali necessarie per calcolare la risposta aumentano in modo quadratico con il numero di termini. Pertanto sono consentiti solo 6 termini in una catena di calcolo per impostazione predefinita (sebbene ciò possa essere aumentato). Per catene di calcolo più lunghe di così, dividi i calcoli in alto, come: nuovo punto (nuovo punto (p1 + p2 + p3 + p4 + p5 + p6) + nuovo punto (p7 + p8 + p9 + p10 + p11 + p12))

La pagina Github .

Oltre a quanto già detto: l'override di .valueOf () può aiutare a produrre un sovraccarico dell'operatore abbastanza potente. Nella prova di concetto Fingers.js puoi aggiungere listener di eventi in stile .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;

L'idea principale è quella di sostituire temporaneamente valueOf quando on () è chiamato:

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.
};

Il numero restituito può quindi essere nuovamente serializzato in funzione utilizzando l'array di gestori. Inoltre, è possibile estrarre i valori dei bit dal valore finale (func1 + func2 - func3) in modo da poter comprendere in modo efficace quali funzioni sono state aggiunte e quali funzioni sono state rimosse.

Puoi controllare l'origine su github e giocare con demo qui .

Esiste una spiegazione completa in questo articolo (è per AS3, difficile dato che è ecmascript funzionerà anche per JS).

Per alcuni casi d'uso limitati puoi avere l'operatore "sovraccarico" Effetti:

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!

Il codice sopra riportato può essere utilizzato gratuitamente con la licenza MIT. YMMV.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top