Los lenguajes de programación suelen tener 2 formas:

  • IMPERATIVO: es decir, como una secuencia de operaciones a realizar.
  • DECLARATIVO: es decir, se especifica el resultado deseado, no cómo lograrlo.

Lenguajes como PHP, Python, JavaScript son IMPERATIVOS: especificamos la secuencia de operaciones utilizando condicionales o ciclos (if, for, etc.)

Ejemplo de código imperativo

En el siguiente fragmento de código, vamos a comenzar declarando una lista de personas en la variable people. Cada persona será un objeto con 2 propiedades: nombre y edad (name y age).

A continuación declararemos un segundo arreglo llamado kid_names, como el nombre lo indica, en este arreglo queremos almacenar nombres de niños (para este ejemplo consideraremos que un niño es una persona con una edad de 12 años o menos).

Luego, vamos a hacer un ciclo de todas las personas, dentro del ciclo verificaremos si la edad de cada persona (person.age) es 12 o menos, de ser así, vamos a incluir el nombre de la persona (person.name) en el arreglo kid_names utilizando el método Array.push provisto por JavaScript.

Finalmente, podremos observar el resultado con el método console.log de JavaScript:

var people = [
  {
    name: 'Aang',
    age: 12,
  },
  {
    name: 'Sokka',
    age: 15,
  },
  {
    name: 'Toph',
    age: 12,
  },
  {
    name: 'Iroh',
    age: 55,
  }
];


var kid_names = [];

for (let person of people) {
  if (person.age <= 12) {
    kid_names.push(person.name);
  }
}

console.log(kid_names);

Esta es la forma imperativa de programar, que describe lo que queremos lograr en términos de «cómo» hacerlo (con un loop y con un condicional) y en vez de «qué» queremos hacer (filtrar y transformar arreglos).

Un problema de esta manera imperativa es que nos anima a mezclar diferentes tareas en un solo lugar. Por ejemplo el ciclo hace dos cosas:

  1. Filtra o excluye a personas de acuerdo a su edad (if (person.age...))
  2. Agrega cadenas de nombres a un nuevo arreglo (kid_names.push(...))

Ejemplo de código declarativo

Lenguajes como SQL soportan otra manera de programar llamada Programación Declarativa.

Con ésta forma DECLARATIVA, especificamos lo que queremos obtener o hacer en lugar de cómo:

SELECT name FROM people AS kids WHERE age <= 12;

Si SQL fuese en español escribiríamos algo como:

SELECCIONE EL nombre DE personas COMO niños DONDE edad <= 12 años;

Obtenemos los nombres de las personas que tienen 12 años o menos «declarando» lo que queremos en lugar de escribir las operaciones para conseguir lo que queremos.

Únete a nuestra comunidad en Discord y comparte con los usuarios y autores de Styde, 100% gratis.

Únete hoy

¿Cuál forma es mejor, imperativa o declarativa?

Ambas formas tienen sus ventajas y desventajas dependiendo del contexto, y es común desarrollar aplicaciones con una mezcla de lenguajes que soportan diversas formas de programar. Por ejemplo, es muy común desarrollar nuestro código backend con PHP pero manejando la base de datos con SQL. En el código frontend podemos usar JavaScript (imperativo) y CSS (declarativo).

Además, hay lenguajes y paradigmas que nos permiten pasar de una forma a otra:

Programación funcional: de imperativo a declarativo

La programación funcional nos permite escribir código declarativo en lenguajes imperativos. Para ello se suelen usar:

Funciones de orden superior

Una función de orden superior es una función (o método) que acepta otra función como argumento.

Array.filter y Array.map son dos ejemplos, ambos métodos aceptan una función como primer argumento y retornarán un nuevo arreglo. Esta es la sintaxis:

var un_nuevo_arreglo = arreglo_original.map_o_filter(funcion_callback);

Partiendo de un arreglo_original llamamos a map o a filter (entre otras funciones) pasando la funcion_callback como argumento y al final de la operación vamos a obtener un_nuevo_arreglo.

Veamos la sintaxis que deberíamos tener para nuestra funcion_callback:

function funcion_callback(item_de_un_arreglo) {
    // alguna operación con item_de_un_arreglo
    return resultado_de_la_operacion;
}

¿Qué es una función callback?

Una función callback es aquella que vamos a pasar como argumento a otra función (de orden superior). Esta función callback no se va a ejecutar en el momento que la pasamos como argumento sino después.

En el caso de funciones de orden superior como filter y map, la función callback se va a ejecutar para cada uno de los items en el arreglo y a su vez va a recibir dicho item como argumento. Ejemplo:

[1, 2, 3].map(function multiplyBy2(number) {

    var result = number * 2;

    console.log(result);

    return result;
});

Puedes ejecutar este código directamente en tu navegador:

  1. Cópialo
  2. Haz click con el botón derecho y selecciona «inspeccionar elemento»
  3. Ve a la pestaña «Consola»
  4. Pega el código allí y presiona «ENTER»
  5. Deberás ver el siguiente resultado:

map in JS console

Puedes ver que la función multiplyBy2 se ejecutó 3 veces y que al final obtuvimos un nuevo arreglo con valores transformados.

Diferencia entre filter y map

Veamos la diferencia entre filter y map:

  • filter Si la función callback devuelve un valor verdadero, el item será incluido en el nuevo arreglo, de lo contrario no.
  • map retorna un nuevo arreglo cuyos valores serán lo que sea que retorne la función callback, permitiéndonos MAniPular los valores del arreglo original.

Ejemplo de programación funcional

Veamos el mismo ejemplo del principio pero escrito de forma funcional y declarativa:

Para trabajar con programación funcional necesitaremos… Funciones. Declaremos dos:

isAKid devolverá verdadero si la persona es un niño, falso de lo contrario. Recuerda que para nuestro ejemplo un niño tiene 12 o menos años de edad.

getName es lo que llamamos un «accessor», es decir una función que nos permitirá acceder y obtener una propiedad, en este caso el nombre de una persona.

function isAKid(person) {
  return person.age <= 12;
}

function getName(person) {
  return person.name
}

A continuación partiendo del arreglo people declarado en el ejemplo inicial, vamos a filtrarlo utilizando filter y la función callback isAKid:

 var only_kids = people.filter(isAKid);

Esto nos devolverá un arreglo con solo niños:

[
    { name: 'Aang', age: 12 },
    { name: 'Toph', age: 12 }
]

Pero nosotros queremos obtener solamente los nombres de los niños. Usemos map para ello:

var kid_names = only_kids.map(getName);

Map transforma el array de objetos en un nuevo array de nombres:

[ 'Aang', 'Toph' ]

Veamos todo el código de una sola vez:

var only_kids = people.filter(isAKid);
var kid_names = people.map(getName);

Debido a que  people.filter(isAKid) retorna un arreglo, podemos encadenar el resultado de llamar al método filter junto al llamado al método map de una sola vez y sin el uso de variables intermedias:

var kid_names = people
    .filter(isAKid)
    .map(getName);

JavaScript también nos permite declarar funciones directamente en línea como argumentos de otras funciones, permitiéndonos así «unificar» todo el código:

var kid_names = people
    .filter(function isAKid(person) {
        return person.age <= 12;
    })
    .map(function getName(person) {
        return person.name
    });

JavaScript, así como otros lenguajes, nos permite declarar funciones de forma «anónima» (funciones sin nombre):

var kid_names = people
    .filter(function (person) {
        return person.age <= 12;
    })
    .map(function (person) {
        return person.name
    });

Nota que he eliminado los nombres de las funciones isAKid y getName; esto es posible si solo quiero llamar a mis funciones «en línea», puesto que no necesito que sean recordadas mediante un nombre o identificador.

JavaScript, a partir de ES6, incluye «Arrow Functions» que nos permiten lograr el mismo resultado, al menos en este ejemplo, pero con una sintaxis más corta («Syntax Sugar»):

var kid_names = people
    .filter((person) => person.age <= 12)
    .map((person) => person.name);

El resultado es el mismo de antes, pero con menos caracteres. Según tu estilo personal puedes terminar prefiriendo la sintaxis más larga o más corta.

Conclusión

Usando funciones de orden superior como map y filter nos acercamos más a la forma DECLARATIVA donde indicamos qué queremos lograr (a través de métodos y operaciones predefinidas) en vez de cómo lograrlo. Es decir, reemplazando total o parcialmente la secuencia de operaciones que solemos definir a través de loops y condicionales.

Continua aprendiendo

Suscríbete a nuestro boletín

Te enviaremos publicaciones con consejos útiles y múltiples recursos para que sigas aprendiendo.

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.