informatica:programacion:cursos:programacion_avanzada_javascript:lambdas
Diferencias
Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
| informatica:programacion:cursos:programacion_avanzada_javascript:lambdas [2024/10/15 13:46] – [DEMO: call, bind y apply] tempwin | informatica:programacion:cursos:programacion_avanzada_javascript:lambdas [2024/10/30 12:49] (actual) – [La pérdida de this (II)] tempwin | ||
|---|---|---|---|
| Línea 55: | Línea 55: | ||
| Las siguientes dos imágenes muestran las diferencias entre ambos entornos: | Las siguientes dos imágenes muestran las diferencias entre ambos entornos: | ||
| - | <WRAP center round todo 60%> | + | {{ : |
| - | Comportamiento en FF | + | |
| - | </ | + | |
| - | <WRAP center round todo 60%> | + | {{ : |
| - | Comportamiento en NodeJs | + | |
| - | </ | + | |
| ==== Sintaxis " | ==== Sintaxis " | ||
| Línea 252: | Línea 248: | ||
| El error que nos da el código anterior es el siguiente (como siempre, el mensaje exacto puede variar según el entorno de JavaScript que uses): | El error que nos da el código anterior es el siguiente (como siempre, el mensaje exacto puede variar según el entorno de JavaScript que uses): | ||
| - | <WRAP center round todo 60%> | + | {{ : |
| - | Error de pérdida de this | + | |
| - | </ | + | |
| El error lo que nos dice es que '' | El error lo que nos dice es que '' | ||
| Línea 262: | Línea 256: | ||
| El siguiente diagrama muestra el valor de '' | El siguiente diagrama muestra el valor de '' | ||
| - | <WRAP center round todo 60%> | + | {{ : |
| - | Valor de this según el bloque de código | + | |
| - | </ | + | |
| Lo importante es tener presente que dentro de la función anónima que se pasa como parámetro a la llamada a '' | Lo importante es tener presente que dentro de la función anónima que se pasa como parámetro a la llamada a '' | ||
| Línea 369: | Línea 361: | ||
| ===== this y funciones definidas con el operador flecha ===== | ===== this y funciones definidas con el operador flecha ===== | ||
| - | Otra de las ventajas de usar el operador flecha para definir funciones, es que las funciones definidas con éste capturan el valor de this existente en el momento de definir la función. Es decir, se evita la " | + | Otra de las ventajas de usar el operador flecha para definir funciones, |
| Observa cómo queda el código anterior usando una función definida con el operador flecha: | Observa cómo queda el código anterior usando una función definida con el operador flecha: | ||
| + | <code javascript> | ||
| var obj = { | var obj = { | ||
| values: [4, 8, 15, 16, 23, 42], | values: [4, 8, 15, 16, 23, 42], | ||
| Línea 381: | Línea 374: | ||
| } | } | ||
| } | } | ||
| + | </ | ||
| - | El código funciona correctamente, | + | El código funciona correctamente, |
| Solo por esto ya tenemos una ventaja clara de usar el operador flecha. | Solo por esto ya tenemos una ventaja clara de usar el operador flecha. | ||
| - | Operador flecha y funciones de primer nivel | + | |
| + | ==== Operador flecha y funciones de primer nivel ==== | ||
| Supón el siguiente código, que usa el operador flecha para definir una función de un objeto: | Supón el siguiente código, que usa el operador flecha para definir una función de un objeto: | ||
| + | <code javascript> | ||
| var obj={ | var obj={ | ||
| nick: ' | nick: ' | ||
| getUrl: () => ' | getUrl: () => ' | ||
| } | } | ||
| + | </ | ||
| - | La pregunta es ¿cuál es el resultado de la función getUrl()? | + | La pregunta es ¿cuál es el resultado de la función |
| - | Si has respondido ' | + | Si has respondido ''%%http:// |
| - | La función getUrl devuelve http:// | + | La función |
| + | <code javascript> | ||
| var obj={ | var obj={ | ||
| nick: ' | nick: ' | ||
| getUrl: function() { return ' | getUrl: function() { return ' | ||
| } | } | ||
| + | </ | ||
| ¿Por qué la función declarada con el operador flecha no funciona y la función declarada a la manera tradicional sí? ¿No se supone que básicamente el operador flecha es un sintaxis más cómoda para declarar funciones? | ¿Por qué la función declarada con el operador flecha no funciona y la función declarada a la manera tradicional sí? ¿No se supone que básicamente el operador flecha es un sintaxis más cómoda para declarar funciones? | ||
| - | Sí, es cierto que el operador flecha es una sintaxis más cómoda para declarar funciones, pero recuerda que, tal y como hemos visto antes, las funciones declaradas con el operador flecha capturan el valor de this existente en el punto de su declaración. Y esta es la clave: el valor de dentro de obj pero fuera de cualquier función es el contexto global. Observa sino el siguiente código: | + | Sí, es cierto que el operador flecha es una sintaxis más cómoda para declarar funciones, pero recuerda que, tal y como hemos visto antes, |
| + | <code javascript> | ||
| var test = { | var test = { | ||
| nick: ' | nick: ' | ||
| url: ' | url: ' | ||
| } | } | ||
| + | </ | ||
| - | El valor de test.url no es http:// | + | El valor de '' |
| - | Ahora bien, cuando usas el operador flecha para definir la función estás capturando el valor de this que existe en este punto y que es el contexto global. Es por eso que la versión que usa el operador flecha no funciona correctamente. A todos los efectos es como si la versión que usa el operador flecha hiciese lo siguiente: | + | Ahora bien, cuando usas el operador flecha para definir la función estás capturando el valor de '' |
| + | <code javascript> | ||
| var obj={ | var obj={ | ||
| nick: ' | nick: ' | ||
| getNick: function() { return ' | getNick: function() { return ' | ||
| } | } | ||
| + | </ | ||
| - | En esta versión usamos bind para forzar la captura del valor de this, que es justamente lo que hace por nosotros el operador flecha y se puede comprobar que tampoco funciona correctamente. | + | En esta versión usamos |
| - | | + | <WRAP center round info 60%> |
| + | En resumen: | ||
| + | </ | ||
| - | El operador flecha y bind | + | ==== El operador flecha y bind ==== |
| - | Se ha visto como el operador flecha captura el valor de this existente y lo propaga como contexto de la función que define. Pero es lógico preguntarse qué sucede si aplicamos bind a una función definida con el operador flecha: | + | Se ha visto como el operador flecha captura el valor de '' |
| + | <code javascript> | ||
| var demo = (() => this.nick).bind({nick: | var demo = (() => this.nick).bind({nick: | ||
| var nick = demo(); | var nick = demo(); | ||
| + | </ | ||
| - | En este código definimos una función con el operador flecha y usamos bind para obtener otra función con su contexto (su valor de this) establecido al objeto {nick: ' | + | En este código definimos una función con el operador flecha y usamos |
| - | Pero la realidad es que el valor de demo() es undefined. La razón es que el operador flecha ya ha capturado el contexto para la función anónima que define y el contexto, una vez capturado ya no puede cambiarse. Es por esto que la llamada a bind no modifica el contexto, por lo que el valor de this se mantiene al que había capturado el operador flecha (el contexto global). | + | Pero la realidad es que el valor de '' |
| - | Eso mismo ocurre si usas bind sobre una función devuelta por otra llamada a bind (el contexto no se modifica por segunda vez): | + | Eso mismo ocurre si usas '' |
| + | <code javascript> | ||
| var demo = function() { return this.nick}.bind({nick:' | var demo = function() { return this.nick}.bind({nick:' | ||
| var demo2 = demo.bind({nick:' | var demo2 = demo.bind({nick:' | ||
| var nick = demo2(); // eiximenis | var nick = demo2(); // eiximenis | ||
| + | </ | ||
| - | ===== ===== | + | ===== DEMO: La propagación de this en el operador flecha |
| + | Consideremos el siguiente objeto: | ||
| + | |||
| + | <code javascript> | ||
| + | var stuff = { | ||
| + | mult: 2, | ||
| + | data: [1, 2, 3, 4], | ||
| + | log: function() { | ||
| + | console.log(" | ||
| + | } | ||
| + | }; | ||
| + | </ | ||
| + | |||
| + | <code javascript> | ||
| + | stuff; // -> Object {mult: 2, data: Array[4], log: stuff.log() } | ||
| + | |||
| + | stuff.log(); | ||
| + | </ | ||
| + | |||
| + | Ahora crearemos una función que devolverá un array con la multiplicación de los elementos del array '' | ||
| + | |||
| + | <code javascript> | ||
| + | var stuff = { | ||
| + | mult: 2, | ||
| + | data: [1, 2, 3, 4], | ||
| + | log: function() { | ||
| + | console.log(" | ||
| + | }, | ||
| + | multData: function() { | ||
| + | return this.data.map(function(e) { | ||
| + | return e * this.mult; | ||
| + | }); | ||
| + | } | ||
| + | }; | ||
| + | </ | ||
| + | |||
| + | Ejecutamos: | ||
| + | |||
| + | <code javascript> | ||
| + | stuff.mult = 10; | ||
| + | |||
| + | var md = stuff.multData(); | ||
| + | |||
| + | md; // -> Array[NaN, NaN, NaN, NaN] | ||
| + | </ | ||
| + | |||
| + | Esto pasa porque en el '' | ||
| + | |||
| + | <code javascript> | ||
| + | var stuff = { | ||
| + | mult: 2, | ||
| + | data: [1, 2, 3, 4], | ||
| + | log: function() { | ||
| + | console.log(" | ||
| + | }, | ||
| + | multData: function() { | ||
| + | return this.data.map(function(e) { | ||
| + | console.log(this); | ||
| + | return e * this.mult; | ||
| + | }); | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | // Ejecutamos: | ||
| + | stuff.multData(); | ||
| + | </ | ||
| + | |||
| + | Esto es lo que se conoce como **pérdida de '' | ||
| + | |||
| + | Una de las soluciones es buscar dónde tiene '' | ||
| + | |||
| + | <code javascript> | ||
| + | var stuff = { | ||
| + | mult: 2, | ||
| + | data: [1, 2, 3, 4], | ||
| + | log: function() { | ||
| + | console.log(" | ||
| + | }, | ||
| + | multData: function() { | ||
| + | var self = this; | ||
| + | return this.data.map(function(e) { | ||
| + | return e * self.mult; | ||
| + | }); | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | // Ejecutamos | ||
| + | stuff.multData(); | ||
| + | </ | ||
| + | |||
| + | Otra forma es utilizando la función '' | ||
| + | |||
| + | <code javascript> | ||
| + | var stuff = { | ||
| + | mult: 2, | ||
| + | data: [1, 2, 3, 4], | ||
| + | log: function() { | ||
| + | console.log(" | ||
| + | }, | ||
| + | multData: function() { | ||
| + | return this.data.map(function(e) { | ||
| + | return e * this.mult; | ||
| + | }.bind(this)); | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | // Ejecutamos | ||
| + | stuff.multData(); | ||
| + | </ | ||
| + | |||
| + | Las funciones definidas con el operador flecha también pueden ser usadas para esto: | ||
| + | |||
| + | <code javascript> | ||
| + | var stuff = { | ||
| + | mult: 2, | ||
| + | data: [1, 2, 3, 4], | ||
| + | log: function() { | ||
| + | console.log(" | ||
| + | }, | ||
| + | multData: function() { | ||
| + | return this.data.map(e => e * this.mult); | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | // Ejecutamos | ||
| + | stuff.multData(); | ||
| + | </ | ||
| ===== Funciones lambda ===== | ===== Funciones lambda ===== | ||
| + | |||
| + | Hasta ahora se ha usado la expresión " | ||
| + | |||
| + | <WRAP center round info 60%> | ||
| + | Esta sección es puramente informativa y se incluye por completitud. El cálculo lambda es un sistema formal que permite definir el concepto de " | ||
| + | </ | ||
| + | |||
| + | ==== Computabilidad ==== | ||
| + | |||
| + | El cálculo lambda es un sistema formal que se usa para verificar la computabilidad, | ||
| + | |||
| + | Lo importante sobre la máquina de Turing en nuestro contexto no es cómo funciona, sino el hecho de que **computacionalmente una máquina de Turing es equivalente al ordenador más potente que podamos construir hoy en día**. Incluso los posiblemente futuros ordenadores cuánticos son equivalentes computacionalmente a una máquina de Turing. Ten presente que " | ||
| + | |||
| + | Puede parecer que cualquier posible problema va a poder ser resuelto, con un tiempo arbitrario (y un consumo arbitrario de ciertos recursos, tales como cinta en una máquina de Turing o memoria en un ordenador actual). Pero la realidad es que esto no es así y **por raro que pueda parecer existen problemas que no pueden ser resueltos con ningún algoritmo, incluso contando con tiempo y recursos ilimitados**. Detectar qué problemas son esos es uno de los objetivos de la teoría de la computabilidad. | ||
| + | |||
| + | ==== El problema de la parada ==== | ||
| + | |||
| + | El problema de la parada es, probablemente, | ||
| + | |||
| + | Su definición es muy simple: dado un programa (a ejecutar por una máquina de Turing, o un ordenador) y su entrada inicial, se trata de decidir si dicho programa (con la entrada suministrada) terminará su ejecución en algún momento o por el contrario estará ejecutándose eternamente (p. ej. en un bucle infinito). El propio Turing demostró que este problema es no computable, es decir, es imposible crear algoritmo alguno que pueda resolverlo. | ||
| + | |||
| + | ==== Cálculo lambda ==== | ||
| + | |||
| + | El cálculo lambda es una herramienta que permite decidir la computabilidad o no de una función determinada. No entraremos aquí en el cómo (echa un vistazo a la [[https:// | ||
| + | |||
| + | Imagina dos funciones. La primera, llamada " | ||
| + | |||
| + | * Identidad: '' | ||
| + | * Suma: '' | ||
| + | |||
| + | El cálculo lambda realiza algunas consideraciones sobre esas funciones. La primera es que **las funciones no necesitan ser explícitamente nombradas**. Así la función " | ||
| + | |||
| + | Otra consideración es que el nombre de los parámetros no tiene importancia alguna. Así las funciones '' | ||
| + | |||
| + | Una tercera consideración interesante es que **toda función que tenga dos parámetros y devuelva un valor puede ser reescrita como una función que tenga un solo parámetro, pero que devuelva otra función, que acepta un parámetro y devuelve un valor**. Este proceso se llama **currificación** y es una de las bases de la programación funcional (por cierto, ¡es posible implementar currificación en JavaScript!). | ||
| + | |||
| + | En el cálculo lambda, las funciones se definen mediante " | ||
| + | |||
| + | <WRAP center round info 60%> | ||
| + | Observa como la notación del operador flecha es casi calcada a la notación de las funciones anónimas (no así a la notación de las propias " | ||
| + | </ | ||
| + | |||
| + | No vamos a contar más cosas sobre el cálculo lambda (ahora ya entraríamos en un territorio mucho más complejo). Tan solo comentar que como sistema formal tiene exactamente la misma potencia computacional que una máquina de Turing, es decir, cualquier algoritmo calculable por una máquina de Turing (lo que significa decir cualquier algoritmo posible) es representable en cálculo lambda. | ||
| + | |||
| + | La importancia del cálculo lambda en el desarrollo de la informática como ciencia es capital (de hecho se podría considerar el cálculo lambda como un (el primer) lenguaje de programación). El cálculo lambda ejerce una gran influencia, especialmente en el desarrollo de lenguajes funcionales tales como LISP o Haskell. | ||
| + | |||
| + | Simplemente quería que supieses de dónde proviene el hecho de que muchos desarrolladores llamemos a las funciones declaradas con el operador flecha, funciones o expresiones lambda. | ||
informatica/programacion/cursos/programacion_avanzada_javascript/lambdas.1728992774.txt.gz · Última modificación: por tempwin
