JavaScript — Funciones (globales, por objeto, constructor, apply), de primera clase, de orden superior, anónimas, IIFE y más…
Temario
- Introducción
- Formas de llamar una función: función global, de objeto, constructor y aplicación
- Funciones de Primera clase (funciones por declaración y por expresión)
- Funciones de orden superior o alto orden
- Funciones anónimas
- Immediately Invoked Function Expression (IIFE)
- Return Statement
- Funciones flecha (Sintaxis básica, primeros pasos, el this, casos especiales)
i. Introducción
En los ejercicios vamos a declarar las variables con var, let o const (por ahora no te preocupes por eso, en el siguiente tema te voy a explicar que hace y como funciona cada una de ellas), así que solo entiendan las funciones…
Una función es un bloque de código que realiza una tarea específica.
Ventajas de usar funciones:
- Nos permiten definir tareas específicas.
- Nos permite evitar duplicidad de código.
- Solo tenemos que llamar a la función para que se ejecute.
ii. Formas de llamar una función
Las funciones pueden invocarse de 4 formas distintas:
- Forma de función global
- Forma de método de un objeto
- Forma de constructor
- Forma de apply
Además es muy importante saber cómo funcionan cada de una de ellas ya que su this no siempre apunta al elemento que nosotros esperamos, veamos cada una de ellas:
a — Forma de función global
Cuando la función es llamada como una función global, this se establece como objeto global, entonces sabemos que window es un objeto global en el navegador, si escribimos this en la consola, debería devolver el objeto de window.
Una función definida a nivel global su this sigue siendo window, ya que su contexto es el mismo (global), veamos el siguiente ejemplo:
La función foo se define a nivel global y su objeto se llama dentro de window, es decir window llama a foo, por lo que window.foo y foo son lo mismo.
Para poder manipular el this, esta forma no es muy útil ya que no podemos trabajar con ella de manera correcta y segura, ya que estaríamos manipulando el this global.
Podemos evitar “equivocarnos”, si hacemos uso del use strict (tocaremos a fondo este tema en use strict**), veamos el siguiente ejemplo:
Podemos observar que el this ya no es global, pero nos va a retornar undefined, digamos que tampoco nos va a se útil, pero podemos evitar trabajar con el this global.
b — Forma de constructor (new)
Si creamos una instancia con el operador new como prefijo, lo que estaremos haciendo es la instancia de la función foo (local), por lo que el contexto de this cambia a ser la función.
c— Forma de método de un objeto
Si creamos un objeto, y dentro creamos una función, el this va a hacer referencia a su objeto:
Solo hay que tener cuidado y ver donde se está ejecutando el contexto de la función, ya que puede cambiar muy fácilmente. Con el ejemplo anterior, solo hagamos un pequeño cambio:
Como podemos observar su contexto ha cambiado, ya que no es el del objeto foo, si no que su contexto es global.
Pero.. entonces.. ¿cómo podemos saber a donde o a quien apunta el this ?
El truco es ver quien es el de la izquierda.
Veamos un ejemplo…
d — Forma de apply
Esta forma de hacerlo nos permite especificar de forma explícita quién va a ser el this de la función, además podemos mandarle un arreglo (apply) o secuencia de parámetros (call); entonces:
El método apply() invoca una determinada función asignando explícitamente el objeto this y un array o similar (array like object) como parámetros (argumentos) para dicha función. [ref]
El método call() llama a una función con un valor this asignado y argumentos provistos de forma individual. [ref]
Sigamos hablando de funciones… en JavaScript, las funciones se definen de dos formas:
- Funciones de primera clase (first-class)
- Entidades de orden superior
iii. Funciones de Primera clase
Las funciones en JavaScript son objetos de primera clase, ya que son objetos que se pueden manipular y transmitir al igual que cualquier otro objeto, es decir es un elemento que soporta todas las operaciones generalmente disponibles para otras entidades importantes como pueden ser los objetos.
En JavaScript tenemos dos tipos de funciones:
- por declaración
- por expresión (asignación a variable)
a — Funciones por declaración
Las funciones declaradas se colocan en la parte superior del ámbito en el que se definen, lo que permite utilizar la función antes de su declaración.
Ejemplo:
El ejemplo anterior es válido, ya que como se explicó: las funciones declaradas se colocan en la parte superior del ámbito.
Realmente JS hace algo así:
b — Expresión
Si estás asignando una función a una variable o propiedad estás tratando con una función por expresión ya que estas se pueden tratar como cualquier otro valor, esto quiere decir que se puede almacenar en variables o propiedades y se puede pasar por parámetros y a su vez devolver funciones.
Para las de expresión, primero debemos definir la función y después usarla, ya que puede generar un error.
Ejemplo:
Una función creada en el contexto de una expresión es también una función por expresión.
iv. Funciones de orden superior o alto orden
Este tema puede ser bastante extenso, por lo que pienso poner aquí solo lo básico, cuando veamos Programación Funcional veremos con lujo de detalle, así que empecemos con un poco de teoría…
Las funciones que llaman a otras funciones o que devuelven funciones, se conocen como funciones de orden superior, muchas veces también recibe el nombre de función de devolución de llamada (callback & promises[ref]).
Entonces las funciones son capaces de:
- Tomar una función como parámetro.
- Retornar la función enviada como parámetro u otra función.
Ejemplo:
En nuestro ejemplo anterior la función validateAge recibe 2 parámetros:
- Una variable numérica (n)
- Una función (isOlder)
Si cumple con la condición invoca la función que se le envió por parámetro.
Veamos un ejemplo mas complejo:
El ejemplo anterior es una forma muy parecida (quizás mal hecha de mi parte) de cómo funciona el map de JS; lo que hace map[ref] es aplicar la función recibida como parámetro sobre cada elemento de una colección (ver loops [ref]para entender cómo funciona).
Ejemplo:
v. Funciones anónimas
JavaScript permite crear funciones anónimas, esto es una función sin nombre:
Las funciones anónimas, también tienen la capacidad de recibir parámetros:
Estas funciones también reciben el nombre de IIFE.
vi. Immediately Invoked Function Expression (IIFE)
Una de las principales razones para usar las IIFE es por la privacidad de los datos, ya que las variables declaradas con var en JavaScript su alcance es a nivel función (en el siguiente post [ref] vemos a fondo este tema), cuando usamos las IIFE, cualquier variable declarada dentro, no puede ser usada fuera:
Otra forma de ejecutar las funciones:
vii. return Statement
En JavaScript las funciones tienen declaraciones de retorno (return statement); esto quiere decir que detiene por completo la ejecución de una función y esta devuelve el control a quien la invocó y además puede o no devolver algún valor, veamos el siguiente ejemplo:
Es importante observar que si no regresamos algún valor, por default la función nos va a regresar el valor undefined, exceptuando cuando se usa el operador new, para este caso nos regresa el this del objeto instanciado, veamos un ejemplo:
viii. Funciones flecha
Las funciones de flecha se recomienda para devoluciones de llamadas (callbacks) o argumentos de función (function arguments)
Usar: Cuando se usa una función de flecha se ejecuta en el contexto de this (comúnmente es lo que buscamos), su sintaxis es más limpia y legible.
No usar: Cuando la función es compleja, aquí se recomienda tener su propia función con nombre.
En los siguientes ejemplos usamos map[ref]…
La expresión de función de flecha (arrow function), sus principales características son:
- Su sintaxis es más corta que una expresión de función.
- No vincula su propio this, arguments, super.
- SIEMPRE son anónimas.
- Son funciones no relacionadas con métodos por lo que NO pueden ser usadas como constructores.
Antes de explicar más a fondo las arrow functions, veamos un ejemplo en ES5 y como quedaría en ES6:
Con ES5
Importante: El map es de ES6, lo que estamos explicando son las funciones…
Con ES6
a — Sintaxis básica
De acuerdo a la documentación de MDN Web Docs de moz://a, su sintaxis básica es la siguiente:
b — Primeros pasos
La inclusión de las arrow functions es por la reducción y simplicidad de código.
c — El this
Uno de los GRANDES problemas que se tiene con las funciones es el this, ya que cada función define su propio valor del this (como lo hemos visto en ejemplos anteriores), lo cual genera muchos problemas y errores al momento de programar, veamos un ejemplo:
Con ES5
Una de las soluciones en ES5 es el famoso self o that
Otra de las soluciones era con el bind
Pero ahora con ES6 y las funciones de flecha es más sencillo y limpio
Con ES6
Las expresiones de función de flecha son las más adecuadas para funciones que no son métodos, ya que por las características que posee te puedes meter en problemas.
Veamos el siguiente ejemplo:
Cuando invocamos obj.b() el this no es el de obj es más bien (para el caso del ejemplo) window, por lo que this.i no existe así que retorna undefined.
Cuando invocamos obj.c() el this si es el de obj, por lo que this.i vale 10.
Si quieres saber más a fondo de cómo funciona bind, call y apply, te recomiendo el post de mi amigo Bruno [ir a].
d — Casos especiales
En la siguiente entrega vamos a ver JavaScript — Scoping
La entrega pasada vimos JavaScript — Tipo de valores
Bibliografía y links que te puede interesar…