Un tutorial (para Javascript) que estoy haciendo sugiere que escribamos una función como esta:
function sayHello() {
//Some comments explaining the next line
window.alert("Hello");
}
Aparte de la ofuscación, ¿hay beneficios al escribir algo como esto en la vida real? Si es así, ¿cuáles son los beneficios?
language-agnostic
functions
Daniel
fuente
fuente
Respuestas:
Perdone mi memoria si tengo esto incorrecto ... Javascript no es mi lenguaje de implementación preferido.
Hay varias razones por las cuales uno desearía que una función sin arg envuelva otra llamada de función. Si bien la simple llamada a
window.alert("Hello");
es algo que podrías imaginar simplemente llama directamente en lugar desayHello()
.Pero, ¿y si hay más? Tienes una docena de lugares donde quieres llamar
sayHello()
y has escrito en suwindow.alert("Hello");
lugar. Ahora quieres que haga unwindow.alert("Hello, it is now " + new Date())
. Si envuelve todas esas llamadas mientrassayHello()
lo cambia en un solo lugar. Si no lo hiciste, lo cambias en una docena de lugares. Esto toca No te repitas . Lo haces porque no quieres tener que hacerlo una docena de veces en el futuro.Trabajé con una biblioteca i18n / l10n en el pasado que usaba funciones para hacer la localización del texto del lado del cliente. Considera la
sayHello()
función. Podría imprimirlohola
cuando el usuario esté localizado en un idioma español. Esto podría verse algo así como:Sin embargo, no es así como funcionaba la biblioteca. En cambio, tenía un conjunto de archivos que se veían así:
Y luego la biblioteca detectaría la configuración del idioma del navegador y luego crearía funciones dinámicas con la localización apropiada como el valor de retorno para una llamada de función sin argumentos basada en el archivo de localización apropiado.
No soy lo suficientemente codificador de Javascript para decir si eso es bueno o malo ... solo que fue y puede ser visto como un posible enfoque.
El punto es que envolver la llamada a otra función en una función propia a menudo es bastante útil y ayuda con la modularización de la aplicación y también puede resultar en un código más fácil de leer.
Aparte de eso, estás trabajando en un tutorial. Es necesario introducir las cosas lo más simple posible al principio. La introducción de llamadas de función de estilo varargs desde el principio puede resultar en un código muy confuso para una persona que no está familiarizada con la codificación en general. Es mucho más fácil pasar de ningún argumento, a argumentos, al estilo varargs, cada uno de los cuales se basa en los ejemplos y la comprensión anteriores.
fuente
window.alert
También se usa a menudo como marcador de posición durante el desarrollo hasta que se pueda diseñar / implementar un buen modo / ventana emergente, por lo que, al igual que el problema del idioma, se puede cambiar mucho más fácilmente. O si ya tiene uno, una actualización de diseño en unos años podría requerir cambios similares.Creo que a veces es útil para ocultar la implementación.
Y esto te da la flexibilidad para cambiarlo más tarde
fuente
centralización: aunque la implementación es una sola línea larga, si es una línea que cambia con frecuencia, probablemente prefiera cambiarla en un solo lugar, que donde sea que se llame sayHello.
minimizar / ocultar dependencias: su código de cliente ya no necesita saber que hay un objeto de ventana, e incluso puede cambiar toda la implementación sin afectar el código del cliente
cumplimiento del contrato: el código del cliente puede esperar un módulo que tenga una función sayHello. En este caso, incluso si es trivial, entonces la función debe estar allí.
consistencia de los niveles de abstracción: si el código del cliente utiliza operaciones de alto nivel, le interesa escribir el código del cliente en términos de 'sayHello, sayBye' y algunas otras funciones 'sayXXX', en lugar de objetos de ventana. De hecho, en el código del cliente, es posible que ni siquiera quiera saber que existe un objeto 'ventana'.
fuente
Es sorprendente que ninguna otra persona haya mencionado las pruebas.
La línea particular "envuelta" que elegiste
window.alert('hello')
, es en realidad un ejemplo perfecto de esto. Cualquier cosa que involucre alwindow
objeto es muy, muy doloroso de probar. Multiplique eso por 1000 veces en su aplicación y le garantizo que los desarrolladores finalmente abandonarán las pruebas. Por otro lado, es bastante fácil simplemente golpear lasayHello
función con un espía y probar que se llamó.Un ejemplo más práctico: porque realmente, ¿quién lo usa realmente
window.alert(...)
en el código de producción? - está comprobando el reloj del sistema. Entonces, por ejemplo, esto estaría envolviendoDateTime.Now
en .NET,time(...)
en C / C ++ oSystem.currentTimeMillis()
en Java. Usted realmente desea para envolver los de una dependencia que se puede inyectar, porque no sólo son (casi) imposible burlarse / falso, de sólo lectura que son y no determinista . Cualquier prueba que cubra una función o método que haga uso directo de la función del reloj del sistema es extremadamente probable que sufra fallas intermitentes y / o aleatorias.El envoltorio real es una función de 1 línea
return DateTime.Now
, pero eso es todo lo que necesita para tomar un objeto no comprobable y mal diseñado y convertirlo en uno limpio y comprobable. Puede sustituir un reloj falso por el envoltorio y configurar su hora a lo que desee. Problema resuelto.fuente
Como dijo Doval, este ejemplo probablemente solo trate de presentarle las funciones. Soy general, sin embargo, es útil. Especialmente especificando algunos, pero no todos, los argumentos, y pasando los otros, puede hacer una función más específica de caso a partir de una función más general. Como un ejemplo algo trivial, considere una función de clasificación que requiere una matriz para ordenar y una función de comparación para ordenar. Al especificar una función de comparación que se compara por valor numérico, puedo hacer una función sortByNumericalValue, y las llamadas a esa función son mucho más claras y concisas.
fuente
El pensamiento detrás de su pregunta parece ser: "¿Por qué no simplemente escribir
alert("Hello");
directamente? Es bastante simple".La respuesta es, en parte, porque realmente no quieres llamar
alert("Hello")
, solo quieres saludar.O: ¿Por qué almacenar contactos en su teléfono, cuando solo puede marcar números de teléfono? Porque no quieres recordar todos esos números; porque marcar números es tedioso y propenso a errores; porque el número puede cambiar, pero sigue siendo la misma persona en el otro extremo. Porque quieres llamar a personas , no a números.
Esto es lo que se entiende por términos como abstracción, indirección, "ocultar detalles de implementación" e incluso "código expresivo".
El mismo razonamiento se aplica al uso de constantes en lugar de escribir valores brutos en todas partes. Usted podría simplemente escribir
3.141592...
cada vez que necesita π, pero por suerte hayMath.PI
.También podríamos mirarnos a nosotros
alert()
mismos. ¿A quién le importa cómo construye y muestra ese diálogo de alerta? Solo desea alertar al usuario. Entre su escrituraalert("Hello")
y el cambio de píxeles en su pantalla, hay una pila profunda y profunda de código y hardware, cada capa le dice a la siguiente lo que quiere, y esa siguiente capa se ocupa de los detalles hasta que la capa más profunda posible voltea algunos bits en el memoria de video.Realmente no quieres tener que hacer todo eso solo para saludar.
La programación, bueno, cualquier tarea, realmente se trata de dividir problemas complejos en partes manejables. Resolver cada fragmento te da un bloque de construcción, y con suficientes bloques de construcción simples, puedes construir cosas grandes.
Es álgebra.
fuente
Es una buena idea mantener el cálculo de valores (expresiones) separado de la ejecución de acciones (declaraciones). Queremos un control preciso sobre dónde y cuándo se tomarán acciones (como mostrar mensajes), pero al calcular los valores, preferimos trabajar a un nivel más abstracto y no tener que preocuparnos por cómo se calculan esos valores.
Una función que solo calcula un valor de retorno, usando solo los argumentos que se dan, se llama pura .
Una "función" que realiza una acción es en realidad un procedimiento , que tiene un efecto .
Todos los efectos causados durante el cálculo de un valor se denominan efectos secundarios , y es mejor evitarlos cuando sea posible ("¡Solo necesitaba esa cadena, no sabía que dañaría la base de datos!").
Para minimizar la posibilidad de efectos secundarios, debemos evitar enviar demasiados datos a nuestros procedimientos, o poner algún cálculo en ellos; Si es necesario realizar algún cálculo de antemano, generalmente es mejor hacerlo por separado en una función pura, luego pasar solo el resultado requerido al procedimiento. Esto mantiene el propósito del procedimiento claro y reduce la posibilidad de que sea reutilizado más tarde como parte de un cálculo (la función pura se puede reutilizar en su lugar).
Por la misma razón, debemos evitar procesar los resultados dentro de un procedimiento. Es mejor devolver el resultado (si lo hay) a nuestra acción y realizar cualquier procesamiento posterior con funciones puras.
Si seguimos estas reglas, podríamos terminar con un procedimiento como
sayHello
, que no necesita ningún dato y no tiene un resultado. Por lo tanto, la mejor interfaz es no tener argumentos y no devolver un valor. Esto es preferible a, por ejemplo, llamar a "console.log" en medio de algún cálculo.Para reducir la necesidad de efectos durante el cálculo, podemos tener cálculos que devuelvan procedimientos ; p.ej. Si necesitamos decidir qué acción tomar, podemos tener una función pura, elegir un procedimiento y devolverlo, en lugar de ejecutarlo directamente.
Del mismo modo, para reducir la necesidad de cálculo durante los procedimientos, podemos hacer que los procedimientos tomen otros procedimientos como parámetros (posiblemente el resultado de una función); p.ej. tomando una serie de procedimientos y ejecutándose uno tras otro.
fuente
setFoo
llamadas, ya que eso implica datos mutables. La alteración del contenido de las variables / propiedades es un efecto que hace que todos los cálculos que utilizan esos datos se vuelvan impuros. No recomendaríaexecute
llamadas per se, pero me gustaría recomendarrunFoo
procedimientos para la ejecución de acciones sobre la base de sus argumentos.Diría que es una combinación de las respuestas dadas por @MichaelT y @Sleiman Jneidi.
Tal vez hay varios lugares en el código donde desea saludar al usuario con un mensaje de saludo para que pueda empaquetar esa idea en un método. En el método, puede traducirlo o expandirlo en un simple 'Hola' mostrando un texto más largo. También es posible que desee utilizar un buen cuadro de diálogo JQuery en lugar de una alerta.
El punto es que la implementación está en un solo lugar. Solo necesita cambiar el código en un solo lugar. (SayHello () es quizás un ejemplo demasiado simple)
fuente