He estado desarrollando complementos jQuery desde hace bastante tiempo, y me gusta pensar que sé cómo diseñar uno bien por ahora. Sin embargo, uno de los problemas sigue fastidiándome, y es cómo lidiar con las funciones privadas de una manera poderosa pero elegante.jQuery plugin patrón de diseño (práctica común?) Para tratar con funciones privadas
Mis plugins generalmente buscan algo como esto:
(function($) {
$.fn.myplugin = function(...) {
...
// some shared functionality, for example:
this.css('background-color', 'green');
...
};
$.fn.mypluginAnotherPublicMethod = function(...) {
...
// some shared functionality, for example:
this.css('background-color', 'red');
...
};
}(jQuery));
Ahora mi pregunta es: ¿cómo secar cuidadosamente hasta que la funcionalidad compartida? Una solución obvia sería para ponerlo en una función dentro del espacio de nombres del plugin:
var fill = function($obj, color) {
$obj.css('background-color', color);
};
Aunque esta solución es efectiva y bien espacio de nombres, no me gusta la misma. Por una simple razón: tengo que pasarle el objeto jQuery. Es decir. Tengo que llamarlo así: fill(this, 'red');
, mientras que quisiera llamar así: this.fill('red');
Por supuesto que podía lograr este resultado con sólo poner en fill
jQuery.fn
. Pero eso se siente muy incómodo. Imagine tener diez complementos desarrollados en base a este enfoque y cada complemento que coloca cinco de esas funciones "privadas" en el espacio de nombres de la función jQuery. Termina en un gran desastre. Podríamos mitigar prefijando cada una de estas funciones con el nombre del complemento al que pertenecen, pero eso realmente no lo hace más atractivo. Se supone que estas funciones son privadas para el complemento, por lo que no queremos exponerlas al mundo exterior (al menos no directamente).
Así que ahí está mi pregunta: ¿alguien de ustedes tiene sugerencias de cómo obtener lo mejor de ambos mundos. Es decir; el código de complemento puede invocar funciones de complemento 'privadas' de forma similar a this.fill('red')
(o this.myplugin.fill('red')
o incluso this.myplugin().fill('red')
etc.), al tiempo que evita la contaminación del espacio de nombres de la función jQuery. Y, por supuesto, debería ser ligero, ya que estas funciones privadas podrían ser llamadas con mucha frecuencia.
ACTUALIZACIÓN: Gracias por sus sugerencias.
Me gusta especialmente la idea de David de definir un tipo de objeto que contiene las funciones 'privadas' y envuelve un objeto jQuery. El único problema es que todavía me impide encadenar funciones 'privadas' y 'públicas'. Lo cual era una gran razón para querer una sintaxis como this.fill('red')
para comenzar.
que terminó con una solución que yo no considero tremendamente elegante, pero apelando a la 'mejor de ambos mundos' causa:
$.fn.chain = function(func) {
return func.apply(this, Array.prototype.slice.call(arguments, 1));
};
que permite construcciones como:
this.
find('.acertainclass').
chain(fill, 'red').
click(function() {
alert("I'm red");
});
I crucé mi pregunta en otros lugares, que también recolectó algunas respuestas interesantes:
- http://forum.jquery.com/topic/jquery-plugin-design-pattern-common-practice-for-dealing-with-private-functions
- http://groups.google.com/group/jquery-en/browse_thread/thread/fa8ccef21ccc589a
Entonces, ¿cómo llenar() mantenerse en el 'esto' de $ .fn.myplugin()? –
no sería 'this' la función' (función (color) {...}) '? – nickf
Creo que estos son los 'this''es en este ejemplo de código: (1)' $ obj.myplugin() ':' $ obj' (2) 'fill()': 'window' (3) 'function (color)': 'window' –