Adoptar las buenas prácticas
Espacio de nombres
1. Aspectos básicos
Al desarrollar, siempre evitaremos exponer demasiadas funciones o variables en el espacio de nombres global, para evitar conflictos de nombres. Esto significa dar acceso solo a lo que es útil y ocultar todo lo demás. Es parecido al principio de una caja negra con entradas y salidas bien definidas, pero la mecánica interna permanece oculta.
Esto es aún más importante si es probable que el código se utilice en otros contextos. El problema es que estamos acostumbrados a agregar funciones a nuestros archivos, sin considerar la reutilización. A medida que nuestro proyecto se vuelve más sustancial, se hace cada vez más difícil de gestionar. La asociación de dos códigos puede causar conflictos que no son necesariamente visibles inicialmente y el resultado se vuelve incierto.
Para limitar las colisiones de nombres, agregaremos un contexto adicional (una especie de super contexto), que asegurará que nuestras funciones y variables no se puedan alterar/usar accidentalmente. Este espacio de nombres es una especie de contenedor de nombres. De esta manera, un nombre solo tiene significado en relación con su espacio de nombres. Por lo tanto, la invocación de una función que no está en el espacio de nombres esperado, no es posible.
Como cada código tiene su propio espacio de nombres, ya no existe ningún riesgo de colisiones asociado con el código que pertenece a otro espacio de nombres.
Un espacio de nombres es una posibilidad asociada con muchos lenguajes. En el lenguaje Java, por ejemplo, la palabra clave package sirve para para realizar la declaración, de manera similar a como se hace en C# con namespace. En JavaScript, lamentablemente no tenemos una palabra clave para este uso, pero tenemos otros trucos igualmente poderosos para conseguirlo.
Este principio es importante para la calidad de sus programas. Una vez que lo entienda, se volverá natural y su desarrollo mejorará aún más.
Cuanto más grande sea su programa, más espacios de nombres necesitará. Es la dimensión que impone su uso. Por tanto, tener en cuenta el espacio de nombres será la garantía de un código de mejor calidad, que podrá evolucionar de forma más sencilla y con más seguridad.
2. Función
a. Función interna...
Módulo
1. Presentación
El concepto de módulo se deriva de la estructura anterior. La idea es ofrecer un formato universal para las piezas funcionales. Un módulo representa una parte independiente de nuestro código. Por ejemplo, podríamos tener un módulo encargado de un tipo de cálculo o un módulo que representa un componente gráfico. Un módulo no se debe confundir con una función; está por encima de la función y oculta todas las funciones y propiedades útiles para la prestación de un servicio.
Anteriormente hemos visto que la función puede servir como un espacio de nombres, que protege frente a conflictos a ciertos métodos o variables de nuestro código. Esto condujo al diseño de nuestro módulo:
function miModulo {
// Definición privada
variables ...
funciones ...
return {
// Definición pública
propiedades...
métodos...
}
}
Esta estructura se puede usar en cualquier lugar e incluso reemplaza a nuestras clases. También podemos devolver un único objeto, un constructor o una función.
Si por ejemplo desea obtener varias instancias, en este caso necesita un constructor que se encargará de generar las instancias bajo demanda:
function miModulo {
// Definición privada
variables para todas las instancias.
funciones ...
// Constructor intermediario para cada instancia
return function() {
return {
// Definición...
CommonJS
1. Presentación
Si queremos hacer un módulo más accesible y, por lo tanto, fácilmente explotable por todos, debemos cumplir con un estándar. De ahí el uso de soluciones como las que ofrece CommonJS (http://www.commonjs.org/). CommonJS nació en 2009 bajo el liderazgo de Kevin Dangoor, con la idea de poder estandarizar ciertas API de JavaScript. Como hemos visto hasta ahora, JavaScript ofrece una gran expresividad en la codificación, lo cual es agradable pero también esconde un problema real de estandarización e interoperabilidad.
2. define
Si miramos la definición de un módulo, se define según CommonJS como:
define( id?, dependencies?, factory);
define es una función ofrecida por la API compatible con CommonJS, que se utiliza para describir un módulo. Los parámetros de esta función (hay un signo de interrogación para un parámetro opcional) son:
-
id: un identificador no obligatorio del módulo. En la práctica no se usará mucho, porque el archivo que engloba el módulo será un id implícito.
-
dependencies: una tabla de identificadores de módulo que se requieren para ejecutar el módulo. Esta tabla es opcional. Cuando se ejecuta el módulo, primero se debe realizar la resolución de las dependencias.
Tenga en cuenta que hay tres dependencias que se pueden utilizar...
AMD
1. Introducción
a. Presentación
AMD significa Asynchronous Module Definition. La idea es basarse en el trabajo de CommonJS (CJS module), para hacer un módulo explotable de manera asíncrona. El uso de un identificador asociado a los módulos también puede ofrecer cierta flexibilidad para tener diferentes mecanismos de resolución, según sea necesario (depuración, prueba, etc.).
La naturaleza asincrónica de esta arquitectura tiene la ventaja de hacer un uso no bloqueante o más bien, bajo demanda. Los recursos se utilizan solo cuando se necesitan. De hecho, es inútil causar una carga global de la que no tendríamos un uso inmediato. Como recordatorio, cuando usamos una etiqueta script en nuestro código HTML con un código externo, la carga de la página está bloqueada mientras no se haya cargado el script (excepto el uso del atributo async en HTML5).
Por otro lado, los frameworks importantes como jQuery, Dojo o Node.js ahora son compatibles con AMD, lo que refuerza aún más el peso de esta arquitectura que puede considerarse perenne.
Cuando hablamos de un módulo AMD, hay que observar más el uso de la función define para la definición del módulo que su funcionamiento. En este último caso, no existe un estándar real y las diferentes implementaciones tienen su propio sistema de invocación de módulos, como veremos.
Un administrador de módulos AMD será el bloque de software JavaScript responsable de resolver los módulos y, por lo tanto, hacerlos funcionar.
El uso de la arquitectura AMD solo se limita a navegadores recientes. Podemos suponer por ejemplo que no habrá ningún problema de uso desde IE 6.
b. Algunos consejos
Cada módulo está presente en un archivo. Un archivo contiene solo un módulo.
Debe adoptar una estructuración de sus módulos en directorios y subdirectorios según el uso deseado para poder obtenerlos de forma más natural. Por ejemplo, si tiene un módulo relacionado con una actividad financiera, esperaríamos encontrarlo en un directorio que se relacione con él.
Según el administrador de módulos AMD, hay que centrarse en las dependencias relativas, es decir, hacer que su módulo se pueda mover fácilmente...
Depurar su código
1. Función alert
a. Uso
La forma más sencilla de generar una traza, es utilizando la función alert. Esta función activa la visualización de un cuadro de diálogo modal (bloqueante), con un mensaje. Su mayor inconveniente es que solo se puede invocar un número reducido de veces, o se corre el riesgo de tener muchas ventanas abiertas en pantalla, que se tienen que cerrar para continuar con su programa. El otro peligro es olvidar eliminar algunas trazas y dejar estos cuadros de diálogo innecesarios en producción.
Ejemplo
for ( var i = 10; i >= 0; i -- ) {
alert( i );
}
En este contraejemplo, tenemos la visualización de un cuadro de diálogo tantas veces como incrementos en el bucle. No hace falta decir que con 11 iteraciones (de 10 a 0 incluidas) es manejable, pero con cien, por ejemplo, esto se vuelve rápidamente abrumador para el usuario.
b. Simplificación
Podemos aligerar estas invocaciones de la siguiente manera:
var tmp = ""
for ( var i = 10; i >= 0; i -- ) {
tmp += " i = " + i + "\n";
}
alert( tmp );
Hemos indicado correctamente la variable i y solo tenemos una única visualización.
El inconveniente sigue siendo una cuestión de cantidad: después de un cierto número de iteraciones, la altura de la ventana hace que todo sea inmanejable.
c. Módulo
En nuestro último caso, podemos distinguir la inicialización de la traza, la modificación de la traza y la visualización de la traza. Estas tres etapas pueden estar disponibles en un módulo muy reducido.
(function( window ) {
var trace = "";
window.trace = function( msg ) {
trace += msg + "\n";
}
window.traceRes = function() {
if ( trace )
alert( trace );
trace = "";
}
} )( window );
// La forma de usarlo se convierte en:
for ( var i = 10; i >= 0; i -- ) {
trace( " i = " + i ); ...