Function
Les funcions són blocs de codi que es poden reutilitzar en altres parts del codi.
Introducció
Funció
Declaració
A continuació tens un exemple de declaració d’una funció:
return a + b
}La paraula reservada function s’utilitza per definir una funció.
A continuació va el nom de la funció:
///
return a + b
}A continuació es defineixen els paràmetres de la funció amb el seu tipus:
//////////////////////
return a + b
}Es pot declarar el tipus del valor que retorna la funció (opcional):
////////
return a + b
}I a continuació és declara el cos de la funció (entre {})
La paraula return finalitza l’execució de la funció i retorna el valor corresponent
Invocar una funció és molt senzill:
resultCos d’una funció
El cos d’una funció pot utilitzar totes les diferents característiques del llenguatge:
- variables
- expressions
if/ else - bucles
whileifor - invocar altres mètodes
- definir altres funcions
A continuació tens un exemple:
return a * 2
}
if a > 5 a += 1000
}
return a + b
}
result // 2120Potser el que més et sorpren és que pots declarar una funció dins d’una funció 😯
Variables
Una variable declarada dins d’una funció només és visible dins de la funció.
Per això tenen el nom de variables locals (a la funció)
Per exemple,
message
}
// Hello, I'm JavaScript!
message // <-- Error! The variable is local to the functionEn canvi, una variable declarara fora d’una funció és accessible per qualsevol funció.
message
}
// Hello, JohnAquestes variables s’anomenen variables globals, i no s’han d’utilitzar.
La funció té accés complet a la variable externa.
També la pot modificar:
userName = 'Bob'
message
}
// Hello, BobLa variable externa només s’utilitza si no n’hi ha una local.
Si es declara una variable amb el mateix nom dins de la funció, aquesta fa “ombra” a l’externa.
Per exemple, en el següent codi la funció utilitza la variable local userName i la variable exterior s’ignora:
message
}
// Hello, AliceParàmetres
Podem passar dades arbitràries a les funcions utilitzant paràmetres.
En el següent exemple, la funció té dos paràmetres: from i text.
`: `
}
'Ann', 'Hello!' // Ann: Hello!
'Ann', "What's up?" // Ann: What's up?Quan es crida la funció, els valors donats es copien a les variables locals from i text. I la funció les utilitza.
Aquí tens un altre exemple: tenim una variable from i la passem a la funció. Tingues en compte que: la funció canvia from, però el canvi no es veu a fora, perquè una funció sempre obté una còpia del valor:
from = // hace que "from" se vea mejor
`: `
}
from, "Hello" // ANN: Hello
// el valor de "from" es el mismo, la función modificó una copia local
from // AnnQuan un valor es passa com a paràmetre d’una funció, també s’anomena argument.
Per deixar els termes clars:
-
Un paràmetre és una variable llistada dins dels parèntesis en la declaració de la funció (és un terme per al moment de la declaració)
-
Un argument és el valor que es passa a la funció quan aquesta és cridada (és el terme per al moment en què es crida).
Declarem funcions llistant els seus paràmetres, després les cridem passant-los arguments.
En l’exemple anterior, es pot dir: “la funció es declara amb dos paràmetres, i després es crida amb dos arguments: from i "Hola"”. showMessage
Retornant un valor
Una funció pot retornar un valor al codi que la crida com a resultat.
L’exemple més simple seria una funció que suma dos valors:
return a + b
}
result // 3La directiva return pot estar a qualsevol lloc de la funció. Quan l’execució l’assoleix, la funció s’atura i el valor es retorna al codi que l’ha cridat (assignat al result anterior).
Pot haver-hi molts return en una sola funció. Per exemple:
if age > 18 return true
} else return '¿Tienes permiso de tus padres?'
}
}
if age 'Acceso otorgado'
} else 'Acceso denegado'
}És possible utilitzar return sense cap valor. Això fa que la funció surti o acabi immediatament.
Per exemple:
if !age return
}
"Mostrándote la película"
// ...
}Paràmetres opcionals
Una funció pot tenir paràmetres opcionals.
Has d’utilitzar el símbol ? per marcar un paràmetre com a opcional.
if x != undefined
x + 10
}
// OK
10 // OKEncara que el paràmetre s’ha especificat com de tipus number, el paràmetre en realitat té el tipus number | undefined.
Els paràmetres opcionals s’han de posar al final.
Paràmetres per defecte
Una altra opció és proporcionar un valor per defecte:
x + 10
}
// 20
10 // 20Ara el paràmetre x sempre serà de tipus number perqué qualsevol argument undefined es reemplaza pel valor 10.
A més, quan un paràmetre és opcional, si vols pots passar undefined com argument i el resultat serà el mateix:
x + 10
}
// 20
10 // 20
undefined // 20Paràmetres rest
Pots definir funcions que prenen un nombre il·limitat d’arguments utilitzant paràmetres rest.
Un paràmetre rest apareix després de tots els altres paràmetres i utilitza la sintaxi ...:
for of xs if x > result
result = x
}
return result
}
10 // 10
10, 30, 15 // 30Variables de funció
A continuació pots veure com pots crear una funció anònima:
El motiu pel qual s’anomena anònim és perquè no està assignat a una variable i, per tant, no té nom.
Si executes el codi no passa res:
> deno test.tsSi vols, pots crear i executar la funció amb ():
//Ara, si executes el codi, es crea la funció anònima i s’executa:
> deno test.ts
HelloTanmateix, una funció anònima, també coneguda com a literal de funció, es pot assignar a una variable per crear una variable de funció:
Això crea una variable de funció anomenada sayHi.
En aquesta expressió, la funció literal original es troba a la part dreta del símbol =:
///////////////////////////////////i el nou nom de la variable es troba al costat esquerre:
/////Paràmetres
Una funció anònima és com qualsevol funció: pot prendre paràmetres i retorna valors
I es crida com qualsevol funció:
result // 4I la podem asignar a una variable:
Igual que la llista de paràmetres d’una funció, això significa que la variable de funció double pren un paràmetre, un number anomenat a.
Ara pots invocar la funció double així:
result // 12A més, quan tens altres funcions del tipus number => number les pots emmagatzemar en una llista:
,
]
for of fs 4
}Si executes el codi, pots veure que s’executen totes les funcions de la llista:
> deno test.ts
8
12Un exemple una mica absurd, però així pots començar a entendre que una funció anònima és un valor que es pot tractar com qualsevol altre valor.
Una funció és un valor
Totes les funcions són un valor, no només les anònimes, i poden estar referenciada per altres variables.
A continuació tens un exemple:
"Hello"
}
// Hello
// Hello El mateix es pot fer amb una variable de funció:
"Hello"
}
// ...TODO explicar inicialització
Funció d’ordre superior
Una funció d’ordre superior (“higher-order function”) és una funció que pren altres funcions com a paràmetres d’entrada o retorna una funció com a resultat.
Escriure una funció que pren paràmetres de funció
Per crear una funció que pren un paràmetre de funció, tot el que has de fer és:
- A la llista de paràmetres de la teva funció, defineix la signatura de la funció que vols acceptar
- Utilitza aquesta funció dins de la teva funció
Per demostrar-ho, aquí tens una funció que pren un paràmetre d’entrada anomenat f, on f és una funció:
}El tipus del paràmetre f indica que f és una funció, i defineix els tipus de funcions que la funció sayHello accepta:
fés el nom del paràmetre d’entrada de la funció. És el mateix que anomenar un paràmtrestringcomso un parametrenumbercomn.- La signatura de tipus de
fespecifica el tipus de funcions que acceptarà aquest funció. - La part
()de la signatura def(a la part esquerra del símbol=>) indica quefno pren paràmetres d’entrada. - La part
voidde la signatura (a la part dreta del símbol=>) indica quefno ha de retornar cap resultat.
Dins de la funció sayHello, s’invoca la funció f que s’ha passat com a paràmetre.
Ara que has definit sayHello, crea una funció que coincideixi amb la signatura de f perquè puguem provar-la.
La funció següent no pren paràmetres d’entrada i no retorna res, de manera que coincideix amb la signatura de tipus de f:
"Hello, David"
}Com que les signatures de tipus coincideixen, pots passar helloDavid a sayHello:
}
"Hello, David"
}
helloDavid // prints "Hello, David"Felicitats 😊! Acabes de definir una funció anomenada sayHello que pren una funció com a paràmetre d’entrada i després invoca aquesta funció al cos de la funció.
Però el més important no és que sayHello pugui prendre una funció com a paràmetre d’entrada; és que pot prendre qualsevol funció que coincideixi amb la signatura de f.
Per exemple, com que la següent funció no pren paràmetres d’entrada i no retorna res, també funciona amb sayHello:
"Bonjour, Juliet"
}> deno test.ts
Bonjour, JulietSintaxis
En aquesta funció:
}Has observat que la signatura de tipus de f és:
voidSaps que això significa, “una funció que no pren paràmetres d’entrada i no retorna res (void)”.
A continuació tens una funció que pren dos paràmetres de tipus number i retorna un number:
f:numberT’imagines quin tipus de funcions coincideixen amb aquesta signatura?
La resposta és que qualsevol funció que pren dos paràmetres number d’entrada i retorna un number coincideix amb aquesta signatura, de manera que totes aquestes “funcions” coincideixen:
return a + b
}
return a - b
}
return a * b
}La funció execute accepta com a paràmetre qualsevol de les tres funcions:
5, 8
}
// ...
sum
subtract
multiplyPots veure que funciona:
> deno test.ts
13
-3
40Prenent un paràmetre de funció juntament amb altres paràmetres
Perquè les funcions d’ordre superior siguin realment útils, també necessiten algunes dades per treballar-hi: per tant, també ha d’acceptar dades com a altres paràmetres d’entrada.
Per exemple, aquí tens una funció anomenada executeNTimes que té dos paràmetres d’entrada: una funció i un number:
while i < n
i += 1
}
}Com mostra el codi, executeNTimes executa la funció f n vegades. Com que un bucle simple com aquest no té valor de retorn, executeNTimes retorna void.
Per provar executeNTimes, defineix una funció que coincideixi amb la signatura de f:
"Hello, world"
}A continuació, passa aquesta funció a executeNTimes juntament amb un number:
helloWord, 3Si executes el codi:
> deno test.ts
Hello, world
Hello, world
Hello, worldExcel·lent🐱. La funció executeNTimes executa la funció helloWorld tres vegades.
Les teves funcions es poden continuar complicant-se com sigui necessari.
Per exemple, aquesta funció pren una funció de tipus (number, number) => number, juntament amb dos paràmetres d’entrada:
result
}Com que les fucions sum i multiply coincideixen amb aquesta signatura de tipus, es poden passar a executeAndPrint juntament amb dos valors number:
result
}
return a + b
}
return a * b
}
sum, 3, 11 // prints 14
multiply, 3, 9 // prints 27Coherència de signatura del tipus de funció
Una bona part d’aprendre sobre les signatures de tipus de funció és que la sintaxi que utilitzes per definir els paràmetres d’entrada de la funció és la mateixa sintaxi que fas servir per escriure literals de funció.
Per exemple, si has d’escriure una funció que calcula la suma de dos nombres enters, la pots escriure així amb un tipus explícit:
return a + b
}Aquest codi consta de la signatura de tipus:
////////////////////////////////
return a + b
}Els paràmetres d’entrada:
//////////////////////////////
return a + b
}i el cos de la funció:
return a + b
/////
}La consistència de TypeScript es mostra aquí, on aquest tipus de funció:
////////////////////////////////
return a + b
}és el mateix que la signatura de tipus que utilitzes per definir un paràmetre d’entrada de funció:
////////////////////////////////
result
}Funcions arrow
Hay otra sintaxis muy simple y concisa para crear funciones, que a menudo es mejor que las Expresiones de funciones.
Se llama “funciones arrow”, porque se ve así:
Esto crea una función f que acepta los parámetros arg1..argN, luego evalúa la expression del lado derecho mediante su uso y devuelve su resultado.
En otras palabras, es la versión más corta de:
return expression
}Veamos un ejemplo concreto:
/* Esta función de flecha es una forma más corta de:
return a + b
}
*/
1, 2 // 3Como puedes ver, (a:number, b:number) => a + b significa una función que acepta dos argumentos llamados a y b.
Tras la ejecución, evalúa la expresión a + b y devuelve el resultado.
Si no hay parámetros, los paréntesis estarán vacíos; pero deben estar presentes:
Las funciones “arrow” se pueden usar de la misma manera que las expresiones de función.
Por ejemplo, para crear dinámicamente una función:
'¡Hola!' :
"¡Saludos!"
Las funciones “arrow” pueden parecer desconocidas y poco legibles al principio, pero eso cambia rápidamente a medida que los ojos se acostumbran a la estructura.
Son muy convenientes para acciones simples de una línea.
Funciones de flecha multilínea
Las funciones de flecha que estuvimos viendo eran muy simples. Toman los parámetros a la izquierda de =>, los evalúan y devuelven la expresión del lado derecho.
A veces necesitamos una función más compleja, con múltiples expresiones o sentencias. En ese caso debemos encerrarlos entre llaves. La diferencia principal es que las llaves necesitan usar un return para devolver un valor (tal como lo hacen las funciones comunes).
Como esto:
return result // si usamos llaves, entonces necesitamos un "return" explícito
};
1, 2 // 3Activitat
1. Implementa la funció map, que retorna una llista en que ha aplicat f a tots els elements de xs:
// TODO
}
result // [ 4, 5, 6 ]Show solution
for of xs x
}
return result
}2. Implementa la funció filter, que retorna una llista amb tots els elements de xs que tornen true quan s’els hi aplica la funció f:
// ...
}
result // [ 3, 4]Show solution
for of xs if x
x
}
return result
}3. Implementa la funció reduce, que retorna un únic resultat a partir d’anar afegint a result el que computi la funció f a partir de result i cada valor x:
for of xs result = result, x
}
return result
}
result // 16Show solution
for of xs result = result, x
}
return result
}4. Donada aquesta llista:
result // 12000Amb les funcions anteriors:
- Filtra tots els element que són positius
- A continuació multiplica per 2 tots els elements que són majors que 10
- A continuació multiplica tots els elements de la llista entre ells.
Show solution
ys = ys, x > 10 ? x * 2 : x
O en una sola linea
Crear una funció que retorna una funció
Imagina que vols escriure una funció greet que retorna una funció.
Aquesta funció agafarà un paràmetre de tipus stringp i l'imprimirà amb console.log()`.
Per simplificar aquest primer exemple, greet no prendrà cap paràmetre d’entrada; només crearà una funció i la retornarà.
Tenint en compte aquesta afirmació, pots començar a construir greet. Ja saps que serà una funció:
També saps que aquesta funció retornarà una funció que (a) pren un paràmetre string i (b) imprimeix aquesta string amb console.log. Per tant, aquesta funció té el tipus string => void:
// ...
}Ara només necessites el cos de la funció. Ja saps que la funció ha de retornar una funció, i aquesta funció pren un string i l’imprimeix. Aquesta funció anònima coincideix amb aquesta descripció:
`Hello, `Ara només has de tornar aquesta funció des de la funció:
return`Hello, `
}Com que aquesta funció retorna una funció, obtens la funció cridant a `greet()p . Aquest és un bon pas per fer al REPL perquè verifica el tipus de la nova funció:
Ara pots invocar a greetFunction:
"David" // prints "Hello, David"Enhorabona, acabes de crear una funció dque retorna una funció i després has executat aquesta funció.
La nostra funció seria més útil si poguéssiu passar una salutació, així que fem-ho. Tot el que has de fer és passar la salutació com a paràmetre a la funció greet i utilitzar-la al string que hi ha dins console.log:
return`, `
}Ara, quan invoques la teva funció, el procés és més flexible perquè pots canviar la salutació, tal com pots veure a continuació:
sayHola és una funció que pren un paràmetre d’entrada de tipus string i retorna void(res).
Ara, quan invoques la funció sayHola la sortida és diferent:
"Laura" // prints "Hello, Laura"Pots crear tantes funcions diferents com vulguis:
"Laura" // prints "Ciao, Laura"Array
La majoria de les vegades les llistes no es processen amb for .. of, sinó que es processen amb funcions de manera funcional.
Les operacions bàsiques són: map, filter, reduce i find.
Amb la funció map pots aplicar una funció a cada element de la llista creant una nova llista:
ys // [ 16, 18, 8, 10, 12 ]Amb la funció reduce pots sumar tots els elements d’una llista:
sum // 32Amb la funció filter pots filtrar els elements d’una llista:
ys // [ 8, 9, 4, 5, 6 ]Pots aplicar les funcions una darrera l’altre:
value != null.
x * 5.
acc + x
ys // 160Activitat
A continuació tens un codi que genera una llista de llistes de números:
,
* 100000))
xssEscriu un codi que torni la llista en què la suma dels seus números és menor:
Show solution
,
* 100000))
.
sum_xs > acc ? sum_xs : acc
resultImplement product(xs) that multiplies all elements of the array.
If the array is empty, it must return 1.
// TODO
}
// 24
// 1Show solution
for of xs result = result * x
}
return result
}