La aplicación de JavaScript Generics

Problema que desea aplicar "genéricos" de JavaScript. Teoría de los lenguajes de programación como Java y C # tienen un concepto de programación llamado medicamentos genéricos. La idea detrás de los medicamentos genéricos es escribir el código de tal manera que un identificador se define como un tipo general que se manipula en una clase o método. Por ejemplo, el código siguiente sería una clase genérica en Java o C #:

clase de contenedores  (Tipo _MANAGED;)

La clase de contenedor tiene un parámetro genérico, Tipo, que puede hacer referencia a cualquier otro tipo. Y en la declaración de contenedores, el miembro de datos _MANAGED es el mismo tipo que el parámetro genérico. En una noción abstracta, gestiona cualquier tipo de contenedores. Un programador de JavaScript podría mirar el código y pensar: "Oye, tengo este ya en JavaScript!" Aquí está el mismo código, esta vez en JavaScript:

la función de contenedores () (this._managed = / * cualquier tipo * /)

Como se ilustra en la receta de 2-8, se puede tener de referencia basados en pato o escribiendo un valor basado en escribir pato. Aplicación de "genéricos" para JavaScript es como la aplicación de un preprocesador, por lo que queremos escribir basado en el valor de pato. El ejemplo de código siguiente muestra lo que puede salir mal cuando se mezcla el valor y el pato de referencia escribiendo juntos:

proxy: la función (ejemplo, funcIdentifier, newFunc) (if (! ejemplo [funcIdentifier]) (throw new error ( "No se puede proxy método inexistente (" + + funcIdentifier ")");) eval ( "var generatedOrigFunc =" + ejemplo [ funcIdentifier]. toString ()); eval ( "var generatedProxyFunc =" + newFunc.toString ());ejemplo [funcIdentifier] = function () ( origFunc var = generatedOrigFunc; proxyFunc var = generatedProxyFunc;var args = new Array (); for (var c1 = 0; c1 <arguments.length; c1 + +) (args.push (argumentos [C1]);) args.push (origFunc); args.push (argumentos) ; proxyFunc.apply (this, args);)),

Este código fuente es un ejemplo de cómo no escribir una aplicación patrón Proxy. El problema de la aplicación se muestra en el código en negrita. Al principio del código en negrita son dos estados eval, que están generando los valores de las variables generatedOrigFunc y generatedProxyFunc. En la instancia de la función incrustada [funcIdentifier], se hace referencia a las variables, y debido al cierre, las variables origFunc y proxyFunc hará referencia a las variables correctas. El concepto de patrón Proxy es que cuando se llama a un método, en primer lugar, llama a la función de referencia por proxyFunc, que luego llama a la función que hace referencia origFunc. Debido proxyFunc se llama en primer lugar, tiene la capacidad de preproceso o post-procesar los datos.

  

El código como escrito trabajará con una única aplicación del patrón Proxy, pero fallará si el patrón de proxy se aplica varias veces. Por ejemplo, imagine la incrustación de código generado del patrón Proxy en un patrón Proxy ya aplicadas. Este código es un ejemplo de gotcha "un" pedazo de código en JavaScript. Fíjate bien en las declaraciones de las variables generatedOrigFunc y generatedProxyFunc qué son referencias a penetrar en el error, pensar en el código proxy de la izquierda como la aplicación proxy 1 (Pi1) y el código de la derecha como la aplicación proxy 2 (pi2). Si una llamada genérica fueron a llamar Pi1, la siguiente secuencia de acontecimientos que tienen lugar:

1. Pi1 se llama.

2. ProxyFunc Pi1 se llama.

3. OrigFunc Pi1 se llama, que es PI2.

4. ProxyFunc PI2 se llama, que es proxyFunc Pi1's.

5. ProxyFunc Pi1 se llama, llamando origFunc Pi1's. Después de estos pasos, usted se dará cuenta de que una recursión está teniendo lugar. La recursividad es debido a la forma de las variables generatedOrigFunc y generatedProxyFunc se declaran. Estas variables se declaran sin ningún tipo de alcance y ámbito de aplicación ya que la función del proxy es amix de uso de referencias con el código de eval. Esta es una mala práctica, ya que algunas variables se serializa y otros no. Queremos una solución, como el preprocesador de C, donde "genéricos" representan la sustitución física de un identificador con un tipo que desee. No queremos un sistema de plantillas. Un sistema de plantillas que se describen a continuación:

<% for (var count = 0; cuenta <10; cuenta + +) (%> Serie [<% = count%>] = GenSeries (<% = count%>) <%}%>

Esto no es lo que queremos porque la legibilidad del código disminuye drásticamente, y, en general, no es necesario. JavaScript es un lenguaje de código dinámico, y muchas de las plantillas de las construcciones se pueden implementar en el código. Es más difícil poner en práctica el cambio de una variable de uso de referencias a la utilización de valores. Solución A modo de ejemplo, vamos a simplificar el patrón Proxy a un único método con una llamada a un método único, como sigue.

 Fuente: / web / ROOT / ajaxrecipes / JavaScript / generics.html función EmbeddedReplace () (var func = __toCall; info ( "Reemplazar", "hola"); func ();)

La función EmbeddedReplace ha declarado una variable local, func. Las funciones de referencias locales variable de la variable __toCall. Después de la declaración de funciones es una llamada a la función de información. La llamada a la función última es la función, que es una llamada a la función __toCall. De mirar únicamente a la utilización de __toCall, no sé mucho acerca de la declaración de que no es una variable global. Para el ámbito de aplicación de esta receta, __toCall es un identificador que será reemplazado. Una llamada de expansión JavaScript sería la siguiente (Voy a discutir los detalles en breve):

EmbeddedReplace = Generics.expand (EmbeddedReplace, (__toCall: function () (info ( "sustituirá en Reemplazar", "hola ");}}); EmbeddedReplace ();

El método Generics.expand tiene dos parámetros. El primer parámetro es la función EmbeddedReplace, que tendrá su aplicación modificada. El segundo parámetro es la estructura del objeto que representa lo que los identificadores serán reemplazados. La estructura del objeto se define de tal manera que el identificador de propiedad define el identificador de ser reemplazado, y el valor asociado a la propiedad es el valor de sustitución.Nota Todo el código presentado aquí utiliza las técnicas de programación estándar de JavaScript. Usted no necesita usar tampones especiales o etiquetas que confunden a los redactores y hacer más complicado para construir fiable, el código de mantener. Cuando el método Generics.expand ha finalizado la ejecución, se genera la declaración siguiente función:

función GeneratedEmbeddedReplace () (var func = (function () (info ( "sustituirá en Reemplazar", "hola");)); info ( "Reemplazar", "hola"); func ();)

El buffer se genera es lo que esperamos, y el comportamiento es lo que esperamos. Cuando se llama a GeneratedEmbeddedReplace, se llama la función incrustada. Para efectos de comparación, vamos a ver cómo esto podría haber funcionado sin la ampliación de una función incrustada:

__toCall function () (info ( "sustituirá en Reemplazar", "hola");) function EmbeddedReplace () (var func = __toCall; info ( "Reemplazar", "hola"); func ();)

Llamadas GeneratedEmbeddedReplace llamará a la función __toCall y comportarse, mirar, y se sienten como en el ejemplo ampliado. Pero ¿por qué haces esto? La referencia basado en la expansión no es una expansión en todos. Usted simplemente han creado una variable global (__toCall) que se pueden asignar en tiempo de ejecución. Con un valor de tipo de expansión, puede tener múltiples funciones con diferentes funcionalidades que no están en conflicto con otros. Debido a que el comportamiento está determinado por la cesión, se puede ejecutar en la situación descrita en la receta de 2-14, donde se comparten las funciones. Si se comparten las funciones, entonces puede surgir un conflicto si se altera la funcionalidad de la función. O usted puede tener una situación en que una función hace una cosa una vez, y otra cosa en otro momento. Para ilustrar el "hacer una cosa ahora, pero no más tarde" problema, considere el escenario siguiente código:

__toCall function () (info ( "sustituirá en Reemplazar", "hola");) function EmbeddedReplace () (info ( "Reemplazar", "hola"); __toCall ();) function llamada () (EmbeddedReplace (); __toCall = function () () EmbeddedReplace ();)

Cuando se llama de llamadas, la primera llamada a EmbeddedReplace resultados en algunas de salida. Luego __toCall es reasignado, y llamando a los resultados EmbeddedReplace de nuevo en la producción de otros que se generan. Tal vez este es el efecto deseado, pero probablemente no lo es. Una manera de resolver el problema consiste en restringir su uso de las capacidades dinámicas de JavaScript. Sin embargo, en este punto me pregunto, ¿por qué estás usando JavaScript y Ajax? Mi opinión es que JavaScript y Ajax representan una evolución en la programación y por lo tanto debe utilizar sus capacidades de comportamiento dinámico.

EmbeddedReplace había sido ampliado, a continuación, modificar __toCall no habría tenido ningún efecto sobre EmbeddedReplace. Y esto es lo que hay que tener en cuenta al escribir código JavaScript. A veces se utilizarán las referencias y, a veces va a utilizar expansiones como los propuestos por los genéricos de JavaScript. Me gustaría añadir un punto más. No es una regla de oro, sino una idea de que en determinados contextos pueden tener su lugar. Imagine por escrito una solicitud en que un pago se calcula sobre la base de la actual tasa de interés diaria. En la mayoría de lenguajes de programación, el pago de interés actual sería una variable que se cargue y se le han asignado en tiempo de ejecución. Uso de medicamentos genéricos de JavaScript y código de conducta basado en el código ampliado podrían emplearse los siguientes:

CalculateInterestPayment función (cantidad) (return amount * 0.04;)

Este código es lo que otros lenguajes de programación llamado no modificable. Se considera codificada porque el número 0.04 se compila en la solicitud y no puede ser cambiado. Pero aquí está la ventaja del código de conducta basado en: el uso de medicamentos genéricos JavaScript, el valor codificado es trivial para el cambio, y mantener a un modelo de programación tradicional en que no es necesario que no tiene ningún sentido en absoluto.

Se utiliza una estrategia de programación no modificable cuando los datos se leer-en su mayoría, O cuando los datos se leen con más frecuencia que está escrito. Tener los datos no modificable puede ser un aumento en el rendimiento, ofrecen una mayor flexibilidad, y simplificar el algoritmo. Uso de medicamentos genéricos JavaScript hoy, el cálculo de intereses es un simple número, pero mañana podría ser el cálculo de un cálculo complejo que utiliza una regla móvil basada en la cantidad que se procesa. Tras haber explicado el por qué, cómo y el cuándo de JavaScript "genéricos", Ahora cubriremos cómo activar JavaScript "genéricos" son ejecutadas. Es un proceso muy simple que consiste en buscar y reemplazar un identificador en un búfer. La plena aplicación es el siguiente.

 Fuente: / website / root / scripts / Common.js Generics var = (ampliar: function (toProcess, itemsToInject) (var bufferToProcess = ops.singleSerialize (toProcess), para (itemToReplace en itemsToInject) (var recurFind = function (startIndex) (var offset = bufferToProcess.indexOf (itemToReplace, startIndex) if (offset == -1) (return;) var = izquierda bufferToProcess.slice (0, offset); derecho var = bufferToProcess.slice (offset + itemToReplace.length); media var = ops.simpleSerialize (itemsToInject [itemToReplace]); bufferToProcess izquierda = + + medio derecho; offset + +; recurFind (offset);) recurFind (0);) genBuffer var = "CLS var =" + bufferToProcess + ";"; eval (genBuffer); CLS return;))

Para ampliar un objeto de JavaScript, el objeto tiene que primero ser convertidos a un búfer. El ops.singleSerialize método convierte cualquier objeto JavaScript en un buffer, y en el caso del ejemplo anterior, convierte el parámetro toProcess en un búfer. Después de la conversión a un buffer, se ha iniciado el proceso de búsqueda de un identificador y su sustitución por el uso de un bucle. Con cada iteración del bucle almacenado en la variable itemToReplace es el identificador de sustituir en bufferToProcess. En el circuito, las referencias recurToFind variable de una función que es llamada de forma recursiva. El propósito de la recursividad es la búsqueda incremental de amortiguamiento para el identificador de reemplazar.

Nota La estrategia de recursión está cubierto en la receta de 2-6. Para encontrar un identificador dentro de bufferToProcess, se utiliza el método indexOf. indexOf tiene dos parámetros: el primer parámetro es el identificador de encontrar, y el segundo parámetro es el índice para iniciar la búsqueda. IndexOf Si no encuentra un identificador, entonces el valor se devuelve -1 y se detiene la recursividad. Si indexOf encuentra el identificador, entonces el índice de donde comienza el identificador es devuelto. Habiendo encontrado el identificador, el buffer se divide en una parte izquierda y una parte de la derecha. Las partes izquierda y derecha se combinan con el texto que se sustituye, y una bufferToProcess se crea una nueva. Cuando no se encuentran los identificadores, el buffer se considera ampliado. El último paso restante es convertir el buffer en una instancia de objeto. Convertir el búfer es un problema porque la ejecución de la función eval de retorno (bufferToProcess) comando podría dar lugar a situaciones impredecibles. Para realizar la conversión previsible, bufferToProcess se concatena con una asignación a la variable CLS. Luego, cuando el nuevo buffer se ejecuta mediante la instrucción eval, el CLS variable local se crea una instancia, y puede ser devuelto a la persona que llama. El código para ampliar y aplicar JavaScript "genéricos" es relativamente simple, pero los efectos son profundos. Cuando se utiliza JavaScript "genéricos", recuerda lo siguiente en mente:

• referencias de JavaScript son más fáciles de aplicar y, en muchos casos, bastante bueno. Sin embargo, como se señaló en la receta de 2-14, las referencias suponen un "gotcha" problema.

• Usted tiene que tomar una decisión entre el uso de referencias para todo y el uso de eval para todo. "Todo lo que" aquí no se refiere a una aplicación completa, pero todo dentro del ámbito de aplicación de un tipo o función. No mezclar las referencias a la declaración eval; hacerlo causará problemas.

• En general, el código es más robusto y estable si se utiliza eval-como las técnicas. Guías de trabajo para los casos simples, pero si su incrusta el código varias veces, a continuación, podría dar lugar a errores.

• Con referencias, se corre el riesgo de que múltiples piezas de código de referencia el mismo código y las mismas variables. Esto puede causar la corrupción y la no debe subestimarse.

• Uso de eval-como estados hace que la depuración más fácil, porque si se serializa una función o un objeto, aparecerá el estado actual del código y así poder seguir lo que es el problema. Si utiliza referencias, se necesita un depurador, y con el código que determina su comportamiento en tiempo de ejecución, la depuración puede ser tedioso.

• Uso de JavaScript "genéricos" como se describe en esta receta es IDE fácil porque no es la creación de topes a mano, y usted no está escribiendo código con etiquetas especiales que IDEs como X-desarrollo, Visual Studio, Komodo y Visual SlickEdit hacer No entiendo.

un artículo presentado por Sonja Lande


Descargo de responsabilidad:Nuestro sitio web no es responsable por el contenido de este artículo. Webarticles es un recurso de información gratuito.
Importante: En este artículo "Implementación de JavaScript Generics", fue traducida por un software automático. Sentimos pena por los errores de ortografía que pueda haber ocurrido. Gracias por su comprensión.


Online: 256 users browsing the articles directory