Ricerca…
Metodo di concatenamento
Il concatenamento dei metodi è una strategia di programmazione che semplifica il tuo codice e lo abbellisce. Il concatenamento del metodo viene eseguito assicurando che ciascun metodo su un oggetto restituisca l'intero oggetto, invece di restituire un singolo elemento di tale oggetto. Per esempio:
function Door() {
this.height = '';
this.width = '';
this.status = 'closed';
}
Door.prototype.open = function() {
this.status = 'opened';
return this;
}
Door.prototype.close = function() {
this.status = 'closed';
return this;
}
Door.prototype.setParams = function(width,height) {
this.width = width;
this.height = height;
return this;
}
Door.prototype.doorStatus = function() {
console.log('The',this.width,'x',this.height,'Door is',this.status);
return this;
}
var smallDoor = new Door();
smallDoor.setParams(20,100).open().doorStatus().close().doorStatus();
Nota che ogni metodo in Door.prototype
restituisce this
, che si riferisce all'intera istanza di quell'oggetto Door
.
Design e catena concatenati dell'oggetto
Chaining and Chainable è una metodologia di progettazione utilizzata per progettare i comportamenti degli oggetti in modo che le chiamate alle funzioni oggetto restituiscano riferimenti a self o a un altro oggetto, fornendo accesso a ulteriori chiamate di funzione che consentono all'istruzione chiamante di concatenare più chiamate senza la necessità di fare riferimento alla variabile che tiene l'oggetto / i
Si dice che gli oggetti che possono essere incatenati siano concatenabili. Se si chiama un oggetto chainable, è necessario assicurarsi che tutti gli oggetti / primitive restituiti siano del tipo corretto. Ci vuole solo una volta affinché il tuo oggetto concatenabile non restituisca il riferimento corretto (è facile dimenticare di aggiungere il return this
) e la persona che utilizza la tua API perderà fiducia ed eviterà di incatenare. Gli oggetti concatenabili dovrebbero essere tutto o niente (non un oggetto concatenabile anche se le parti lo sono). Un oggetto non dovrebbe essere chiamato concatenabile se solo alcune delle sue funzioni sono.
Oggetto progettato per essere concatenabile
function Vec(x = 0, y = 0){
this.x = x;
this.y = y;
// the new keyword implicitly implies the return type
// as this and thus is chainable by default.
}
Vec.prototype = {
add : function(vec){
this.x += vec.x;
this.y += vec.y;
return this; // return reference to self to allow chaining of function calls
},
scale : function(val){
this.x *= val;
this.y *= val;
return this; // return reference to self to allow chaining of function calls
},
log :function(val){
console.log(this.x + ' : ' + this.y);
return this;
},
clone : function(){
return new Vec(this.x,this.y);
}
}
Esempio di concatenamento
var vec = new Vec();
vec.add({x:10,y:10})
.add({x:10,y:10})
.log() // console output "20 : 20"
.add({x:10,y:10})
.scale(1/30)
.log() // console output "1 : 1"
.clone() // returns a new instance of the object
.scale(2) // from which you can continue chaining
.log()
Non creare ambiguità nel tipo di reso
Non tutte le chiamate di funzione restituiscono un tipo concatenabile utile, né restituiscono sempre un riferimento a se stessi. È qui che l'uso del buon senso del naming è importante. Nell'esempio sopra la chiamata di funzione .clone()
non è ambigua. Altri esempi sono .toString()
implica che viene restituita una stringa.
Un esempio di nome di una funzione ambigua in un oggetto concatenabile.
// line object represents a line
line.rotate(1)
.vec(); // ambiguous you don't need to be looking up docs while writing.
line.rotate(1)
.asVec() // unambiguous implies the return type is the line as a vec (vector)
.add({x:10,y:10)
// toVec is just as good as long as the programmer can use the naming
// to infer the return type
Convenzione di sintassi
Non esiste una sintassi di utilizzo formale durante il concatenamento. La convenzione è quella di concatenare le chiamate su una singola riga se breve o concatenare sulla nuova riga rientrata di una scheda dall'oggetto referenziato con il punto sulla nuova riga. L'uso del punto e virgola è facoltativo, ma aiuta indicando chiaramente la fine della catena.
vec.scale(2).add({x:2,y:2}).log(); // for short chains
vec.scale(2) // or alternate syntax
.add({x:2,y:2})
.log(); // semicolon makes it clear the chain ends here
// and sometimes though not necessary
vec.scale(2)
.add({x:2,y:2})
.clone() // clone adds a new reference to the chain
.log(); // indenting to signify the new reference
// for chains in chains
vec.scale(2)
.add({x:2,y:2})
.add(vec1.add({x:2,y:2}) // a chain as an argument
.add({x:2,y:2}) // is indented
.scale(2))
.log();
// or sometimes
vec.scale(2)
.add({x:2,y:2})
.add(vec1.add({x:2,y:2}) // a chain as an argument
.add({x:2,y:2}) // is indented
.scale(2)
).log(); // the argument list is closed on the new line
Una cattiva sintassi
vec // new line before the first function call
.scale() // can make it unclear what the intention is
.log();
vec. // the dot on the end of the line
scale(2). // is very difficult to see in a mass of code
scale(1/2); // and will likely frustrate as can easily be missed
// when trying to locate bugs
Lato sinistro del compito
Quando si assegnano i risultati di una catena, viene assegnata l'ultima chiamata di ritorno o il riferimento a un oggetto.
var vec2 = vec.scale(2)
.add(x:1,y:10)
.clone(); // the last returned result is assigned
// vec2 is a clone of vec after the scale and add
Nell'esempio sopra vec2
viene assegnato il valore restituito dall'ultima chiamata nella catena. In questo caso, sarebbe una copia di vec
dopo la scala e aggiungere.
Sommario
Il vantaggio di cambiare è più chiaro codice più gestibile. Alcune persone lo preferiscono e rendono concatenabile un requisito quando selezionano un'API. Vi è anche un vantaggio in termini di prestazioni poiché consente di evitare di dover creare variabili per conservare risultati intermedi. Con l'ultima parola, gli oggetti concatenabili possono essere usati in modo convenzionale così da non forzare il concatenamento rendendo un oggetto concatenabile.