¿Programación modular JS? cuales son las normas
Conceptos básicos
Primero demos una breve descripción general de algunos patrones modulares desde que Eric Miraglia (el desarrollador de YUI) publicó por primera vez un blog que describe el patrón modular hace tres años. Si ya está muy familiarizado con estos modos modulares, puede omitir esta sección y comenzar a leer desde el "Modo Avanzado".
Cierre anónimo
Esta es una estructura básica que hace que todo sea posible y también es la mejor característica de Javascript. Simplemente crearemos una función anónima y la ejecutaremos inmediatamente. Todo el código se ejecutará dentro de esta función y vivirá en un cierre que proporciona privatización, lo cual es suficiente para que las variables en estos cierres estén disponibles durante todo el ciclo de vida de nuestra aplicación.
Copia el código de la siguiente manera:
(function () {
// ... todas las variables y funciones están solo en este alcance
// todavía mantiene el acceso a todos los globales
}());
Tenga en cuenta el par de corchetes más externos que envuelven la función anónima. Debido a las características del lenguaje Javascript, este par de paréntesis es necesario. En JavaScript, las declaraciones que comienzan con la palabra clave function siempre se consideran declaraciones de función. Envolver este código entre paréntesis le dice al intérprete que es una expresión de función.
Importación de variables globales
Javascript tiene una característica llamada variables globales implícitas. No importa dónde se use el nombre de una variable, el intérprete seguirá la cadena de alcance hacia atrás para encontrar la declaración var de la variable. Si no se encuentra ninguna declaración var, la variable se trata como una variable global. Si esta variable se utiliza en una declaración de asignación y la variable no existe, se creará una variable global. Esto significa que es fácil de usar o crear variables globales en cierres anónimos. Desafortunadamente, esto puede conducir a un código que es extremadamente difícil de mantener, porque para el ojo humano es imposible saber qué variables son globales de un vistazo.
Afortunadamente, nuestra función anónima proporciona una solución alternativa sencilla. Simplemente pasando variables globales como argumentos a nuestras funciones anónimas, obtenemos un código más limpio y más rápido que las variables globales implícitas. Aquí tienes un ejemplo:
Copia el código de la siguiente manera:
(function ($, YAHOO) {
// ahora tienes acceso a jQuery global (como $) y YAHOO en este código
}(jQuery, YAHOO));
Exportación de módulo
A veces no solo quieres usar variables globales, también desea declararlos para uso repetido. Podemos hacer esto fácilmente exportándolos, a través del valor de retorno de la función anónima.
Hacer esto completará un prototipo básico del patrón modular, y seguirá un ejemplo completo:
Copia el código de la siguiente manera:
var MODULE = (function () {
var my = {},
privateVariable = 1;
función privateMethod() {
// ...
}
mi.moduleProperty = 1;
my.moduleMethod = función () {
// ...
};
return my;
}());
Tenga en cuenta que hemos declarado un módulo global llamado MÓDULO, que tiene 2 propiedades públicas: un método. llamado MODULE.moduleMethod y una variable llamada MODULE.moduleProperty. Además, mantiene un estado integrado privado mediante cierres de funciones anónimos. Al mismo tiempo, podemos importar fácilmente las variables globales que necesitamos y usar este patrón modular como aprendimos antes.
Modo avanzado
La base descrita en la sección anterior es suficiente para muchas situaciones. Ahora podemos desarrollar aún más este modo modular para crear una estructura más poderosa y escalable. Comencemos con el módulo MÓDULO e introduzcamos estos modos avanzados uno por uno.
Modo amplificar
Es una limitación del modo modular que todo el módulo debe estar en un solo archivo. Cualquiera que haya trabajado en un proyecto grande comprenderá el valor de dividir js en varios archivos. Afortunadamente, tenemos una excelente implementación para amplificar módulos. Primero, importamos un módulo, le agregamos propiedades y finalmente lo exportamos. Aquí hay un ejemplo, amplíelo desde el MÓDULO original:
Copie el código de la siguiente manera:
var MÓDULO = (función (mi) {
mi .anotherMethod = function () {
// método agregado...
};
devolver mi;
}(MÓDULO ));
Utilizamos la palabra clave var para garantizar la coherencia, aunque no es necesaria aquí. Después de ejecutar este código, nuestro módulo ya tiene un nuevo método público llamado MODULE.anotherMethod. El archivo de amplificación también mantiene su propio estado integrado privado y objetos importados.
Modo de amplificación amplia
Nuestro ejemplo anterior requiere que nuestro módulo de inicialización se ejecute primero y luego se puede ejecutar el módulo de amplificación. Por supuesto, a veces esto puede no ser necesariamente necesario. Una de las mejores cosas que puede hacer una aplicación Javascript para mejorar el rendimiento es ejecutar scripts de forma asincrónica. Podemos crear módulos flexibles de varias partes y permitir que se carguen en cualquier orden mediante el modo de ampliación permisivo. Cada archivo debe organizarse según la siguiente estructura:
Copia el código de la siguiente manera:
var MODULE = (function (my) {
// agregar capacidades...
return my;
}(MODULE || {}));
En este modo, se requiere la expresión var. Tenga en cuenta que si MODULE no se ha inicializado, esta declaración de importación creará MODULE. Esto significa que puede utilizar una herramienta como LABjs para cargar todos los archivos de su módulo en paralelo sin bloquearse.
Modo de amplificación ajustada
El modo de amplificación amplia es excelente, pero también trae algunas limitaciones a tus módulos. Lo más importante es que no se pueden anular de forma segura las propiedades de un módulo. Tampoco puede usar propiedades de otros archivos durante la inicialización (pero puede usarlas en tiempo de ejecución). El modo de amplificación estricta implica una secuencia secuencial de cargas y permite anular propiedades. Aquí hay un ejemplo simple (ampliando nuestro MÓDULO original):
Copia el código de la siguiente manera:
var MÓDULO = (función (mi) {
var old_moduleMethod = my.moduleMethod;
my.moduleMethod = function () {
// anulación del método, tiene acceso a old a través de old_moduleMethod...
} ;
return my;
}(MODULE));
Anulamos la implementación de MODULE.moduleMethod en el ejemplo anterior, pero cuando sea necesario, usted Puede mantener una referencia al método original.
Clonación y herencia
Copia el código de la siguiente manera:
var MODULE_TWO = (function (old) {
var my = { } ,
clave;
for (ingrese antiguo) {
if (old.hasOwnProperty(clave)) {
mi [ clave] = antiguo[clave];
}
}
var super_moduleMethod = antiguo.moduleMethod;
my.moduleMethod = function () {
// método de anulación en el clon, acceso a super a través de super_moduleMethod
};
devolver mi;
} (MODULE));
Este modo es probablemente la opción menos flexible. Hace que el código parezca más limpio, pero eso tiene el costo de la flexibilidad. Como escribí anteriormente, si una propiedad es un objeto o función, no se copiará, sino que se convertirá en una segunda referencia al objeto o función. Modificar uno de ellos modificará el otro al mismo tiempo (Nota del traductor: ¡Porque son básicamente iguales!). Este problema de clonación de objetos se puede resolver mediante el proceso de clonación recursiva, pero es posible que la clonación de funciones no pueda resolverlo. Quizás se pueda usar eval para resolverlo. Por lo tanto, describo este método en este artículo sólo para que esté completo.
Variables privadas entre archivos
Existe una limitación importante al dividir un módulo en varios archivos: cada archivo mantiene sus propias variables privadas y no puede acceder a otras variables privadas. Pero este problema se puede solucionar.
A continuación se muestra un ejemplo de un módulo indulgente que mantiene variables privadas entre archivos:
Copie el código de la siguiente manera:
var MODULE = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || función () {
eliminar my._private;
eliminar mi._seal;
eliminar mi._unseal;
},
_unseal = my._unseal = mi._unseal | | función () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
//acceso permanente a _private, _seal y _unseal
return my;
}(MODULE || {})); p>
p>
Todos los archivos pueden establecer atributos en sus respectivas variables _privadas, y se entiende que otros archivos pueden acceder a ellos. Una vez cargado este módulo, la aplicación puede llamar a MODULE._seal() para evitar llamadas externas al _private interno. Si es necesario cambiar la escala del módulo, los métodos internos en cualquiera de los archivos pueden llamar a _unseal() antes de cargar el nuevo archivo y llamar a _seal() nuevamente después de que se haya ejecutado el nuevo archivo. Utilizo este patrón en el trabajo hoy y no he visto este enfoque en ningún otro lugar. Creo que este es un patrón muy útil y vale la pena escribir un artículo sobre el patrón en sí.
Submódulos
Nuestro último modo avanzado es obviamente el más simple. Hay muchos ejemplos excelentes de creación de submódulos. Esto es como crear un módulo normal:
Copia el código de la siguiente manera:
MODULE.sub = (function() {
var my = {} ;
// ...
devolver mi;
}());
Aunque esto parece simple, creo que es vale la pena mencionar aquí. Los submódulos tienen todas las ventajas avanzadas de los módulos generales, incluido el modo de amplificación y el estado de privatización.