Zoeken…
Methode Chaining
Methodeketting is een programmeerstrategie die uw code vereenvoudigt en verfraait. Methode chaining wordt gedaan door ervoor te zorgen dat elke methode op een object het hele object retourneert, in plaats van een enkel element van dat object te retourneren. Bijvoorbeeld:
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();
Merk op dat elke methode in Door.prototype
this
retourneert, wat verwijst naar de volledige instantie van dat Door
object.
Chainable objectontwerp en kettingvorming
Chaining en Chainable is een ontwerpmethodologie die wordt gebruikt om objectgedrag te ontwerpen, zodat aanroepen van objectfuncties verwijzingen naar zichzelf of een ander object retourneren, waardoor toegang wordt geboden tot extra functie-aanroepen waardoor het aanroepende statement vele gesprekken aan elkaar kan koppelen zonder te hoeven verwijzen naar de variabele holding het object / de objecten.
Van objecten die kunnen worden geketend, wordt gezegd dat ze ketenbaar zijn. Als u een te koppelen object aanroept, moet u ervoor zorgen dat alle geretourneerde objecten / primitieven van het juiste type zijn. Het duurt slechts een keer voor uw schakelbare object niet de juiste referentie (makkelijk om te vergeten toe te voegen terug return this
) en de persoon met behulp van uw API zal vertrouwen en voorkomen chaining verliezen. Kettingbare objecten moeten alles of niets zijn (geen kettingbaar object, zelfs als er onderdelen zijn). Een object mag niet ketenbaar worden genoemd als slechts enkele van zijn functies dat zijn.
Object ontworpen om te ketenen
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);
}
}
Chaining-voorbeeld
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()
Creëer geen dubbelzinnigheid in het retourtype
Niet alle functieaanroepen retourneren een bruikbaar ketentype, noch geven ze altijd een verwijzing naar zichzelf terug. Dit is waar gezond verstand gebruik van naamgeving belangrijk is. In het bovenstaande voorbeeld is de functieaanroep .clone()
ondubbelzinnig. Andere voorbeelden zijn .toString()
houdt in dat een string wordt geretourneerd.
Een voorbeeld van een dubbelzinnige functienaam in een ketenbaar object.
// 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
Syntaxisconventie
Er is geen formele gebruikssyntaxis bij het koppelen. De conventie is om de aanroepen op een enkele regel te koppelen als deze kort is of om op de nieuwe regel een tab van het verwezen object te laten inspringen met de stip op de nieuwe regel. Gebruik van de puntkomma is optioneel, maar helpt door het einde van de keten duidelijk aan te duiden.
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
Een slechte syntaxis
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
Linkerkant van opdracht
Wanneer u de resultaten van een keten toewijst, wordt de laatste terugkerende oproep of objectreferentie toegewezen.
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
In het bovenstaande voorbeeld wordt vec2
toegewezen aan de waarde die is geretourneerd door de laatste aanroep in de keten. In dit geval zou dat een kopie zijn van vec
na de schaal en toevoegen.
Samenvatting
Het voordeel van wijzigen is duidelijkere, beter te onderhouden code. Sommige mensen geven er de voorkeur aan en zullen kettingplicht een vereiste maken bij het selecteren van een API. Er is ook een prestatievoordeel, omdat u hiermee geen variabelen hoeft te maken om tussentijdse resultaten te behouden. Met als laatste woord dat kettingbare objecten ook op een conventionele manier kunnen worden gebruikt, zodat je geen chaining afdwingt door een object kettingbaar te maken.