Salta el contingut

Funcions

Una funció és un bloc de codi que realitza una tasca determinada.
Les funcions ens permeten reutlitzar blocs de codi en diferents punts de l'execució dels nostres programes.

Una funció s'executa quan la invoquem amb l'operador ().

Sintaxi

Podem definir les nostres pròpies funcions en JavaScript seguint aquesta estructura:

function nom_funció( [ paràmetre1, paràmetre2, ... ] )
{
    instruccions a executar;

    [ return valor; ]
}

Una funció pot rebre paràmetres i retornar un valor de retorn.
Tant els paràmetres com el valor de retorn són opcionals.
Els paràmetres es reben dins dels parèntesis () en el moment d'invocar la funció.
Dins de la funció els paràmetres es comporten com variables locals.

Diferència entre paràmetres i arguments

Els paràmetres s'indiquen a la declaració d'una funció:

//a, b i c són paràmetres
function exemple( a, b, c ) { ... }

Els arguments es passen quan es crida una funció:

// Els valors 1, 2 i 3 són arguments
exemple( 1, 2, 3 );

Atenció

Si accedim a una funció sense els () se'ns retornarà la funció i no el resultat de la seva execució.

Nom de les funcions

Quan definim el nom de les funcions cal tenir en compte que:

Valors de retorn

Idealment, una funció sempre hauria de retornar un valor.
Una funció que no contigui la sentència return retornarà el valor undefined.

Quan el codi arriba a una instrucció return dins d'una funció, l'execució de la funció s'atura immediatament.

function exemple(a, b) {
    if ( a == 3 ) return b // Si a == 3 la funció retorna b i acaba
    return a               // Si a != 3 la funció retorna a i acaba
    return 0               // Mai s'executarà aquesta instrucció
}

Variables dins de funcions

Les variables declarades dins d'una funció utilitzant var o let són locals de la funció.

// el codi que posem aquí NO pot utilitzar la variable "nom"

function exemple() {
  var nom = "Joan";

  // el codi que posem aquí POT utilitzar la variable "nom"
}

// el codi que posem aquí NO pot utilitzar la variable "nom"

Nombre d'arguments

Si invoquem una funció amb més arguments que paràmetres té declarats, els arguments sobrants són ignorats i no es produeix cap error.

function exemple( a, b ) { ... }

// El tercer argument no es té en compte
exemple( 10, 20, 30 );

Si invoquem una funció amb menys arguments dels paràmetres que té declarats, els que falten s'inicialitzen com a no definits (undefined):

function exemple( a, b, c ) { ... }

// El paràmetre 'c' rebrà el valor undefined
exemple( 10, 20 );

Valor per defecte dels paràmetres

Amb ES5 (ECMAScript 5) calia comprovar l'existència dels arguments dins del codi de la funció i inicialitzar-los a un valor per defecte si no en tenien:

function exemple( valor ) {
  if ( valor === undefined) x = 10;
  return valor * 2;
}

Des de la versió ES6 de JavaScript es poden definir valors per defecte pels paràmetres amb = en el moment de declarar la funció.

function exemple( valor = 10 ) {
    return valor * 2;
}

exemple(1) // Retornarà 2
exemple() // Retornarà 20

Ús en l'actualitat

Tots els navegadors moderns ja suporten ES6 i podem assignar valors per defecte directament amb =

Paràmetres per valor i per referència

Els paràmetres de tipus primitius (cadenes, numèrics i booleans) es passen sempre per valor, per tant es modifica el valor dels arguments passats a la funció.

Els paràmetres que siguin de tipus array o objecte es passen per referència.
Si es modifica algun dels seus elements dins de la funció, es modificarà també l'array o objecte original fora de la funció.

let x = [ 'valor_inicial' ];

function f( p ) {
    p[0] = 'valor_nou';
}

f( x ); // x[0] = 'valor_nou'

Funcions anònimes

Són aquelles en les que ometem el nom de la funció.
Normalment s'utilitzen quan volem definir un bloc de codi que només s'ha d'executar en un punt concret del programa, i per tant no cal utilitzar un nom de funció ja que no la invocarem enlloc més.

Com a conseqüència no les podem invocar pel nom però sí que les podem:

  • assignar com a argument d'una altra funció
setInterval( function() { ... }, 1000 );
  • assignar a una variable o a un esdeveniment
element.onclick = function() { ... };
(function (a) { return a + 10 })(10) // Retorna 20

This

La paraula reservada this fa referència a un objecte, que variarà segons diferents casos:

  • Sol o dins d'una funció, fa referència a l'objecte global.
  • Dins d'un mètode d'un objecte, fa referència al propi objecte.
  • Dins d'un esdeveniment fa referència a l'element HTML que ha rebut l'esdeveniment.

Excepció

Si tenim activat el mode estricte, this dins d'una funció retorna undefined enlloc de l'objecte global.

Nota

this no és una variable sinó una paraula reservada del llenguatge.
No podem canviar el valor de this.

Cal tenir clar quin és el context de this en cada moment.

Per exemple, si assignem una funció directament a un esdeveniment onclick, dins de la funció this farà referència a l'elemenent que ha rebut l'esdeveniment, per tant el que s'hagi clicat:

function pintaVermell() {
    // Dins d'aquesta funció 'this' representa l'element HTML clicat
    this.style.color = "white";
    this.style.backgroundColor = "red";
}

// Assignem la funció directament a l'esdeveniment click de cada botó,
// sense posar () al final ja que provocaria l'execucio de la funció
document.getElementById("boto_1").onclick = pintaVermell;
document.getElementById("boto_2").onclick = pintaVermell;
document.getElementById("boto_3").onclick = pintaVermell(); // <-- ERROR!

En canvi, si enlloc d'assignar directament una funció a l'esdeveniment li assignem una funció anònima, tindrem la referència a this dins del context de la funció anònima, però no més enllà. Si l'hem de passar a una altra funció ho podem fer com a argument:

function pintaColor(element, colorText, colorFons) {
    // Dins d'aquesta funció 'this' representa l'objecte global (Window)
    // i 'element' és un paràmetre que representa l'objecte que volem modificar
    element.style.color = colorText;
    element.style.backgroundColor = colorFons;
}

document.getElementById("boto_1").onclick = function() {
    // Dins d'aquesta funció 'this' representa el botó clicat (HTML),
    // i el podem passar com a paràmetre a una altra funció
    pintaColor(this, "white", "red");
};

Expressions de funcions

Les expressions de funcions es declaren com un assignació de variable, però se'ls passa com a valor una funció:

let exemple = function ( a ) {
    return a + 20;
}

exemple( 10 ); // Retorna 30

En aquest cas la variable exemple és de tipus funció, i conté el codi de la funció assignada:

typeof( exemple ); // Retorna 'function'

exemple.toString(); // Retorna 'function (a) { return a+20;}'

Les funcions es poden declarar en qualsevol punt del codi, però les podem invocar abans d'haver-les declarat gràcies al Hoisting.
En canvi les expressions de funcions no existeixen fins que l'execució del codi arriba a la línia on se les assigna a una variable.

Les expressions de funcions es poden reassignar, a diferència de les funcions que no es poden redeclarar en temps d'execució.
D'aquesta manera una mateixa crida a una expressió de funció pot estar invocant funcions diferents segons requereixi el nostre codi.

let suma10 = function (x) { return x + 10 }
let mult10 = function (x) { return x * 10 }

let f = suma10

f( 10 ); // Retorna 20

let f = mult10

f( 10 ); // Retorna 100

let f = suma10() // <-- ERROR, aquí no estem assignant la funció
                 //     sinó el valor que retorna (NaN)

Funcions fletxa (arrow functions)

Són una notació alternativa i més compacta per declarar funcions.

Es comporten igual que les funcions declarades amb function però cal tenir en compte que:

  • no canvien el context de this al seu interior, sinó que mantenen el context del punt on s'ha invocat la funció fletxa
  • no es poden utilitzar com a constructors
  • sempre són anònimes

Sintaxi comparada amb les funcions anònimes tradicionals:

    function ( a ) {
        return a + 100;
    }

S'elimina la paraula reservada function i posem una fletxa (=>) entre ( ) i { }

    ( a ) => { return a + 100; }

Si la funció només té una línia i retorna un valor, no cal posar les claus { } i el return es fa implícitament

    ( a ) => a + 100;

Si hi ha un sol paràmetre, podem ometre els parèntesis

    a => a + 100;

Funcions predefinides del llenguatge

Són funcions integrades per defecte en el llenguatge JavaScript i que podem fer servir quan les necessitem.

encodeURI()

Codifica una URI en format UTF-8 de manera que els caràcters especials que contingui es puguin transportar correctament, per exemple dins de capçaleres HTTP.
No codifica els següents caràcters: , / ? : @ & = + $ #
Si necessitem codificar tots els caràcters, podem fer-ho amb la variant encodeURIComponent

let text = encodeURI("Això està força bé");

decodeURI()

Fa la funció inversa de encodeURI() i descodifica els caràcters especials d'una URI de manera que es pugui recuperar el text original.
Existeixen també les variants encodeURIComponent / decodeURIComponent que converteixen un major conjunt de caràcters

let text = decodeURI("Aix%C3%B2%20est%C3%A0%20for%C3%A7a%20b%C3%A9");

eval()

Retorna el resultat d'avaluar una expressió o executar instruccions de JavaScript.
Si s'utilitza correctament pot ser molt potent però també és molt perillosa ja que permet la injecció de codi.

Atenció

Executar JavaScript a partir del contingut d'una cadena es considera un risc important, per tant es recomana evitar sempre l'ús de la funció eval().

isFinite()

Ens indica si un valor és un número vàlid.

isNaN()

Ens indica si el valor passat com a paràmetre no és un número.

Number()

Converteix el valor passat com a paràmetre en un valor numèric si és possible

String()

Converteix el valor passat com a paràmetre a una cadena.

parseInt()

Converteix el valor passat a un número enter, amb la particularitat que intenten fer la conversió fins a trobar el primer caràcter no numèric.

parseFloat()

Converteix el valor passat a un número amb coma flotant, amb la particularitat que intenten fer la conversió fins a trobar el primer caràcter no numèric.