Sök…
Metodkedja
Metodkedjning är en programmeringsstrategi som förenklar din kod och förskönar den. Metodkedjning görs genom att säkerställa att varje metod på ett objekt returnerar hela objektet istället för att returnera ett enda element i det objektet. Till exempel:
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();
Observera att varje metod i Door.prototype
returnerar this
, vilket avser hela instansen av det Door
objektet.
Kedjanbar design och kedja
Chaining and Chainable är en designmetodik som används för att designa objektbeteenden så att samtal till objektfunktioner returnerar referenser till mig själv, eller ett annat objekt, vilket ger åtkomst till ytterligare funktionssamtal som gör att samtalsmeddelandet kan kedja samman många samtal utan att behöva referera till variabeln objektet.
Föremål som kan kedjas sägs vara kedjbara. Om du kallar ett objekt som kan kedjas, bör du se till att alla returnerade objekt / primitiv är av rätt typ. Det tar bara en gång för ditt kedjebärbara objekt att inte returnera rätt referens (lätt att glömma att lägga till return this
) och personen som använder ditt API kommer att förlora förtroende och undvika kedja. Kedjbara objekt bör vara allt eller ingenting (inte ett kedjbart objekt även om delar är). Ett objekt bör inte kallas kedjanbart om bara några av dess funktioner är.
Objekt designat för att vara kedjbart
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);
}
}
Exempel på kedja
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()
Skapa inte tvetydighet i returtypen
Inte alla funktionssamtal returnerar en användbar kedjanbar typ, och de returnerar inte alltid en referens till mig själv. Det är här användningen av namngivning av sunt förnuft är viktigt. I exemplet ovan är funktionssamtalet .clone()
otvetydigt. Andra exempel är .toString()
innebär att en sträng returneras.
Ett exempel på ett tvetydigt funktionsnamn i ett kedjanbart objekt.
// 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
Syntaxkonvention
Det finns ingen formell syntax för användning vid kedja. Konventionen är att antingen kedja samtal på en enda rad om den är kort eller att kedja på den nya raden indragna en flik från det refererade objektet med punkten på den nya raden. Användning av semikolon är valfri men hjälper till genom att tydligt beteckna kedjans ände.
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
En dålig syntax
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
Vänster sida av uppdraget
När du tilldelar resultaten från en kedja tilldelas det senast återkommande samtalet eller objektreferensen.
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
I exemplet vec2
tilldelas vec2
värdet som returnerades från det senaste samtalet i kedjan. I det här fallet skulle det vara en kopia av vec
efter skalan och lägga till.
Sammanfattning
Fördelen med att ändra är tydligare mer underhållbar kod. Vissa människor föredrar det och kommer att göra ett kedjan möjligt när de väljer ett API. Det finns också en prestationsfördel eftersom det gör att du kan undvika att skapa variabler för att hålla delresultat. Med det sista ordet är att kedjbara objekt kan användas på ett konventionellt sätt så att du inte verkställer kedjan genom att göra ett objekt kedjbart.