Programación con JavaScript > Sesión 06
Crear constructores a partir de los cuales se puedan instanciar múltiples objetos.
Como vimos en la sesión anterior existen distintos paradigmas de programación. La programación funcional es un paradigma declarativo, es decir, se enfoca en el qué se desea lograr sin preocuparse mucho en el cómo (el lenguaje de programación se encarga de esta parte).
var numbers = [1, 2, 3, 4, 5];
var doubles = [];
for(var i = 0; i < numbers.length; i++) {
doubles.push(numbers[i] * 2);
}
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(doubles); // [2, 4, 6, 8, 10]Este es un ejemplo de código imperativo. Generalmente usar ciclos es programación imperativa pues queda del lado del programador controlar cuándo iniciar, cuándo terminar y qué hacer en cada ciclo.
var numbers = [1, 2, 3, 4, 5];
var doubles = numbers.map(function(number) {
return number * 2;
});
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(doubles); // [2, 4, 6, 8, 10]Esta es la forma declarativa del mismo código. Ambos fragmentos de código hacen exactamente lo mismo, crear un arreglo doubles con el doble de cada elemento del arreglo numbers. La diferencia con el segundo ejemplo es que hacemos uso del método map(), el programador no se encarga de controlar cuándo y dónde terminar el ciclo, sólo se encarga del resultado, obtener el doble de cada elemento dentro de numbers.
El método map() crea un nuevo array con los resultados de la llamada a la función indicada aplicados a cada uno de sus elementos.
Decimos que algo es mutable cuando puede ser cambiado o modificado. Por lo tanto, inmutable es algo que no puede ser alterado. En términos de programación, las variables inmutables nunca cambian su valor. Este es un principio muy importante en la programación funcional, de hecho, lenguajes de programación como Elixir o Erlang no permiten la mutación de variables.
En lugar de alterar una variable, creamos nuevos valores y reemplazamos los antiguos. Si bien JavaScript no es puramente funcional, es lo suficientemente flexible como para permitir o pretender serlo.
Para llevar este concepto a la práctica es importante siempre preferir crear una nueva variable en lugar de intentar modificar la original. Esto se puede llevar a cabo con métodos como map() que no altera el arreglo original, o bien creando tus propias funciones inmutables.
Para que una función pueda ser considerada pura debe cumplir dos reglas:
-
El valor retornado siempre es el mismo cuando se da el mismo valor de entrada.
-
No debe producir side effects (efectos secundarios).
El primer punto se refiere a que si ejecutamos la misma función varias veces con los mismos argumentos siempre obtendremos el mismo resultado.
function add(a, b) {
return a + b;
}Podemos llamar las veces que queramos la esta función de la forma add(1, 2) y sabemos que siempre vamos a obtener el mismo resultado 3.
function randomNumber() {
return Math.floor(Math.random() * 10);
}Esta función no cumple la primera regla porque si la llamamos 10 veces, obtendremos cada vez un número aleatorio entre 1 y 10. No podemos predecir el valor de retorno de esta función.
Los side effects son un término más amplio que el anterior. A grandes rasgos significa modificar algo fuera de la función. Algunos ejemplos:
-
Mutar los parámetros que recibe una función como en el Ejemplo 1.
-
Modificar cualquier variable fuera de la función.
-
Llamadas a una API.
-
console.log()
La función anterior add() también cumple con la segunda regla, no produce side effects. Sólamente está trabajando con las variables que recibe la función y siempre retorna un valor.
En un lenguaje de programación se dice que una función es de primera clase cuando puede ser tratada como cualquier otra variable. Por ejemplo, cuando puede ser pasada como argumento a otras funciones o cuando puede ser asignada a una variable. Este comportamiento no es explusivo de JavaScript, otros lenguajes de programación como R o Scala también cuentan con esta característica.
Ya hemos guardado funciones anónimas en una variable anteriormente.
var square = function(number) {
return number * number;
}
var squareOfFour = square(4);
console.log(squareOfFour); // 16Por lo tanto, las expresiones de funciones como estas son consideradas funciones de primera clase.
Cuando una función recibe otra función como parámetro se le llama de alto orden o de orden superior. JavaScript nos proporciona varias funciones de alto orden para trabajar con estructuras de datos. Las más usadas son map(), filter() y reduce().
Al principio de la sesión vimos cómo funciona map(), aplica una función sobre cada elemento del arreglo. Es importante destacar que no muta el arreglo original.
var numbers = [1, 2, 3, 4, 5];
var doubles = numbers.map(function(number) {
return number * 2;
});
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(doubles); // [2, 4, 6, 8, 10]De igual forma filter() crea un nuevo arreglo pero sólo con aquellos elementos que retornen true por la función que actúa como predicado.
var numbers = [1, 2, 3, 4, 5];
var evenNumbers = numbers.filter(function(number) {
return number % 2 === 0;
});
console.log(evenNumbers); // [2, 4]Por último, reduce() acumula o reduce todos los elementos a un valor único según la función dada.
var numbers = [1, 2, 3, 4, 5];
var sum = numbers.reduce(function(accumulator, currentValue) {
return accumulator + currentValue;
}, 0); // Initial value
console.log(sum); // 15