Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:programacion_avanzada_javascript:lambdas

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
informatica:programacion:cursos:programacion_avanzada_javascript:lambdas [2024/10/15 13:53] – [this y funciones definidas con el operador flecha] tempwininformatica: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%> +{{ :informatica:programacion:cursos:programacion_avanzada_javascript:11-funcion-var-firefox.png |}}
-Comportamiento en FF +
-</WRAP>+
  
-<WRAP center round todo 60%> +{{ :informatica:programacion:cursos:programacion_avanzada_javascript:11-funcion-var-nodejs.png |}}
-Comportamiento en NodeJs +
-</WRAP>+
  
 ==== Sintaxis "verbose" ==== ==== Sintaxis "verbose" ====
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%> +{{ :informatica:programacion:cursos:programacion_avanzada_javascript:11-error-perdida-this.png |}}
-Error de pérdida de this +
-</WRAP>+
  
 El error lo que nos dice es que ''this.filter'' no es una función. Pero la función ''filter'' sí que está definida en el objeto... El error lo que nos dice es que ''this.filter'' no es una función. Pero la función ''filter'' sí que está definida en el objeto...
Línea 262: Línea 256:
 El siguiente diagrama muestra el valor de ''this'' dentro de cada bloque de código: El siguiente diagrama muestra el valor de ''this'' dentro de cada bloque de código:
  
-<WRAP center round todo 60%> +{{ :informatica:programacion:cursos:programacion_avanzada_javascript:11-error-perdida-this-02.png |}}
-Valor de this según el bloque de código +
-</WRAP>+
  
 Lo importante es tener presente que dentro de la función anónima que se pasa como parámetro a la llamada a ''Array.prototype.filter'' el valor de ''this'' no es el propio objeto ''obj'', sino que es el contexto global. De ahí que recibamos el error de que ''this.filter()'' no es una función. Lo importante es tener presente que dentro de la función anónima que se pasa como parámetro a la llamada a ''Array.prototype.filter'' el valor de ''this'' no es el propio objeto ''obj'', sino que es el contexto global. De ahí que recibamos el error de que ''this.filter()'' no es una función.
Línea 463: Línea 455:
 ===== DEMO: La propagación de this en el operador flecha ===== ===== 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("mult -> ", this.mult, "data -> ", this.data)
 +    }
 +};
 +</code>
 +
 +<code javascript>
 +stuff; // -> Object {mult: 2, data: Array[4], log: stuff.log() }
 +
 +stuff.log(); // -> mult-> 2 data -> Array [1, 2, 3, 4 ]
 +</code>
 +
 +Ahora crearemos una función que devolverá un array con la multiplicación de los elementos del array ''data'':
 +
 +<code javascript>
 +var stuff = {
 +    mult: 2,
 +    data: [1, 2, 3, 4],
 +    log: function() {
 +        console.log("mult -> ", this.mult, "data -> ", this.data)
 +    },
 +    multData: function() {
 +        return this.data.map(function(e) {
 +            return e * this.mult;
 +        });
 +    }
 +};
 +</code>
 +
 +Ejecutamos:
 +
 +<code javascript>
 +stuff.mult = 10;
 +
 +var md = stuff.multData();
 +
 +md; // -> Array[NaN, NaN, NaN, NaN]
 +</code>
 +
 +Esto pasa porque en el ''return e * this.mult;'', ''this'' ha perdido su valor. Podemos comprobarlo añadiendo un ''console.log'':
 +
 +<code javascript>
 +var stuff = {
 +    mult: 2,
 +    data: [1, 2, 3, 4],
 +    log: function() {
 +        console.log("mult -> ", this.mult, "data -> ", this.data)
 +    },
 +    multData: function() {
 +        return this.data.map(function(e) {
 +            console.log(this);
 +            return e * this.mult;
 +        });
 +    }
 +};
 +
 +// Ejecutamos:
 +stuff.multData(); // -> Window, Window, Window, Window. Es el contexto global.
 +</code>
 +
 +Esto es lo que se conoce como **pérdida de ''this'' en JavaScript**.
 +
 +Una de las soluciones es buscar dónde tiene ''this'' un valor correcto y lo guardamos:
 +
 +<code javascript>
 +var stuff = {
 +    mult: 2,
 +    data: [1, 2, 3, 4],
 +    log: function() {
 +        console.log("mult -> ", this.mult, "data -> ", this.data)
 +    },
 +    multData: function() {
 +        var self = this;
 +        return this.data.map(function(e) {
 +            return e * self.mult;
 +        });
 +    }
 +};
 +
 +// Ejecutamos
 +stuff.multData(); // -> Array [2, 4, 6, 8]
 +</code>
 +
 +Otra forma es utilizando la función ''bind'':
 +
 +<code javascript>
 +var stuff = {
 +    mult: 2,
 +    data: [1, 2, 3, 4],
 +    log: function() {
 +        console.log("mult -> ", this.mult, "data -> ", this.data)
 +    },
 +    multData: function() {
 +        return this.data.map(function(e) {
 +            return e * this.mult;
 +        }.bind(this));
 +    }
 +};
 +
 +// Ejecutamos
 +stuff.multData(); // -> Array [2, 4, 6, 8]
 +</code>
 +
 +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("mult -> ", this.mult, "data -> ", this.data)
 +    },
 +    multData: function() {
 +        return this.data.map(e => e * this.mult);
 +    }
 +};
 +
 +// Ejecutamos
 +stuff.multData(); // -> Array [2, 4, 6, 8]
 +</code>
 ===== Funciones lambda ===== ===== Funciones lambda =====
 +
 +Hasta ahora se ha usado la expresión "funciones declaradas con el operador flecha". En cierta literatura puedes encontrar el término //arrow function// (que se traduciría por "función flecha") pero lo más normal es que **mucha gente se refiera a las funciones declaradas con el operador flecha como funciones lambda (o incluso expresiones lambda)**. De hecho, ésta será la nomenclatura que se usará de ahora en adelante en el curso. Esta nomenclatura proviene del [[https://es.wikipedia.org/wiki/C%C3%A1lculo_lambda|cálculo lambda]].
 +
 +<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 "función computable". Aunque no tiene nada que ver explícitamente con JavaScript, esta sección incluye un poco de historia y cultura básica de la informática. De todos modos, si el tema te parece tedioso, puedes saltártela sin problemas.
 +</WRAP>
 +
 +==== Computabilidad ====
 +
 +El cálculo lambda es un sistema formal que se usa para verificar la computabilidad, es decir determinar qué problemas son solucionables mediante un algoritmo con una máquina de Turing. La máquina de Turing es un dispositivo muy simple, que básicamente manipula una serie de símbolos escritos sobre una tira de cinta de acuerdo a un sistema de reglas. Es más un dispositivo imaginario que real (aunque se puede construir), ideado por el matemático [[https://es.wikipedia.org/wiki/Alan_Turing|Alan Turing]].
 +
 +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 "computacionalmente equivalente" no implica que puedan resolver el mismo problema en el mismo tiempo, implica que ambos (la máquina de Turing y el ordenador) pueden resolver el problema. Es decir, finalizarán la ejecución del algoritmo con un resultado final.
 +
 +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, el problema no computable más famoso (aunque no el único).
 +
 +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://es.wikipedia.org/wiki/Tesis_de_Church-Turing|tesis de Church-Turing]] para más información). Pero simplemente quiero que veas, muy por encima, la notación del cálculo lambda y sus consideraciones principales.
 +
 +Imagina dos funciones. La primera, llamada "Identidad", devuelve el mismo argumento que se le pasa y la segunda, llamada "Suma", devuelve la suma de los dos argumentos que recibe. Matemáticamente las podríamos definir:
 +
 +  * Identidad: ''I(x) = x''
 +  * Suma: ''S(x, y) = x + y''
 +
 +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 "Suma" puede ser reescrita como una función anónima: ''x,y -> x + y'' y la función "Identidad" puede ser reescrita como ''x -> x''.
 +
 +Otra consideración es que el nombre de los parámetros no tiene importancia alguna. Así las funciones ''x -> x'' e ''y -> y'' son la misma.
 +
 +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 "expresiones lambda" que indican qué debe hacerse con su argumento. Se les llama "expresiones lambda" porque se usa la letra griega lambda para definir la lista de argumentos. Así la "expresión lambda" ''λx. x + 2'' representa a la función anónima ''x -> x + 2''.
 +
 +<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 "expresiones lambda") aunque son notaciones equivalentes.
 +</WRAP>
 +
 +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.1728993232.txt.gz · Última modificación: por tempwin