Buscar..
Método de encadenamiento
El encadenamiento de métodos es una estrategia de programación que simplifica su código y lo embellece. El encadenamiento de métodos se realiza al garantizar que cada método en un objeto devuelve el objeto completo, en lugar de devolver un solo elemento de ese objeto. Por ejemplo:
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();
Tenga en cuenta que cada método en Door.prototype
devuelve this
, que se refiere a la instancia completa de ese objeto Door
.
Encuadernación y diseño de objetos.
Chaining and Chainable es una metodología de diseño que se utiliza para diseñar comportamientos de objetos de modo que las llamadas a funciones de objetos devuelvan referencias a sí mismos u otro objeto, brindando acceso a llamadas de función adicionales que permiten que la instrucción de la llamada encadene muchas llamadas sin la necesidad de hacer referencia a la variable que se sostiene. los objetos.
Los objetos que pueden ser encadenados se dice que son viables. Si llama a un objeto chainable, debe asegurarse de que todos los objetos / primitivos devueltos sean del tipo correcto. Solo se necesita una vez para que su objeto chainable no devuelva la referencia correcta (es fácil olvidarse de agregar return this
) y la persona que usa su API perderá la confianza y evitará el encadenamiento. Los objetos chaables deben ser todos o nada (no un objeto chainable aunque sean partes). Un objeto no debe ser llamado chainable si solo algunas de sus funciones lo son.
Objeto diseñado para ser chainable.
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);
}
}
Ejemplo de encadenamiento
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()
No cree ambigüedad en el tipo de retorno
No todas las llamadas de función devuelven un tipo útil y no siempre devuelven una referencia a sí mismo. Aquí es donde el uso del sentido común es importante. En el ejemplo anterior, la llamada a la función .clone()
no es ambigua. Otros ejemplos son .toString()
implica que se devuelve una cadena.
Un ejemplo de un nombre de función ambiguo en un objeto que se puede cambiar.
// 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
Convención de sintaxis
No hay una sintaxis de uso formal cuando se encadena. La convención es encadenar las llamadas en una sola línea si es corta o encadenar en la nueva línea con sangría una pestaña del objeto al que se hace referencia con el punto en la nueva línea. El uso del punto y coma es opcional pero ayuda al denotar claramente el final de la cadena.
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 mala sintaxis
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
Lado izquierdo de la asignación
Cuando asigna los resultados de una cadena, se asigna la última llamada devuelta u referencia de objeto.
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
En el ejemplo anterior, al vec2
se le asigna el valor devuelto desde la última llamada en la cadena. En este caso, eso sería una copia de vec
después de la escala y agregar.
Resumen
La ventaja de cambiar es el código más claro y fácil de mantener. Algunas personas lo prefieren y harán un requisito obligatorio al seleccionar una API. También hay un beneficio de rendimiento, ya que le permite evitar tener que crear variables para mantener los resultados provisionales. Con la última palabra es que los objetos susceptibles de ser utilizados también se pueden utilizar de una manera convencional, de modo que no impone el encadenamiento al hacer que un objeto sea posible.