Funcions
Introducció
Section titled “Introducció”Funció
Section titled “Funció”Declaració
Section titled “Declaració”A continuació tens un exemple de declaració d’una funció:
function sum(a: number, b: number): number { return a + b}
La paraula reservada function
s’utilitza per definir una funció.
A continuació va el nom de la funció:
function sum(a: number, b: number): number { /// return a + b}
A continuació es defineixen els paràmetres de la funció amb el seu tipus:
function sum(a: number, b: number): number { ////////////////////// return a + b}
Es pot declarar el tipus del valor que retorna la funció (opcional):
function sum(a: number, b: number): number { //////// 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:
const result = sum(3, 4)console.log(result)
Cos d’una funció
Section titled “Cos d’una funció”El cos d’una funció pot utilitzar totes les diferents característiques del llenguatge:
- variables
- expressions
if/ else
- bucles
while
ifor
- invocar altres mètodes
- definir altres funcions
A continuació tens un exemple:
function happySum(a: number, b: number) {
function double(a: number) { return a * 2 }
if (a > 5) { a += 1000 }
return double(a + b)}
const result = happySum(10, 50)console.log(result) // 2120
Potser el que més et sorpren és que pots declarar una funció dins d’una funció 😯
Variables
Section titled “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,
function showMessage() { let message = "Hello, I'm TypeScript!" // local variable console.log(message)}
showMessage() // Hello, I'm JavaScript!console.log(message) // <-- Error! The variable is local to the function
En canvi, una variable declarara fora d’una funció és accessible per qualsevol funció.
let userName = 'John'
function showMessage() { let message = `Hello, ${userName}` alert(message)}
showMessage() // Hello, John
Aquestes 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:
let userName = 'John'
function showMessage() { userName = 'Bob' let message = `Hello, ${userName}` alert(message)}
showMessage() // Hello, Bob
La 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:
let userName = 'John'
function showMessage() { let userName = 'Alice' let message = `Hello, ${userName}` alert(message)}
showMessage() // Hello, Alice
Paràmetres
Section titled “Parà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
.
function showMessage(from: string, text: string) { // parameters: from, text console.log(`${from}: ${text} `)}
showMessage('Ann', 'Hello!') // Ann: Hello!showMessage('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:
function showMessage(from: string, text: string) { from = from.toUpperCase() // hace que "from" se vea mejor console.log(`${from}: ${text}`)}
let from = "Ann"
showMessage(from, "Hello") // ANN: Hello
// el valor de "from" es el mismo, la función modificó una copia localconsole.log(from) // Ann
Quan 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
Section titled “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:
function sum(a: number, b: number) { return a + b}
let result = sum(1, 2)console.log(result) // 3
La 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:
function checkAge(age: number) { if (age > 18) { return true } else { return confirm('¿Tienes permiso de tus padres?') }}
let age = Number(prompt('¿Qué edad tienes?', "18"))
if (checkAge(age)) { alert('Acceso otorgado')} else { alert('Acceso denegado')}
És possible utilitzar return
sense cap valor. Això fa que la funció surti o acabi immediatament.
Per exemple:
function showMovie(age: number) { if ( !checkAge(age) ) { return }
alert( "Mostrándote la película" ) // ... }
Paràmetres opcionals
Section titled “Paràmetres opcionals”Una funció pot tenir paràmetres opcionals.
Has d’utilitzar el símbol ?
per marcar un paràmetre com a opcional.
function f(x?: number) { if (x != undefined) console.log(x + 10)}
f() // OKf(10) // OK
Encara 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
Section titled “Paràmetres per defecte”Una altra opció és proporcionar un valor per defecte:
function f(x: number = 10) { console.log(x + 10)}
f() // 20f(10) // 20
Ara 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:
function f(x: number = 10) { console.log(x + 10)}
f() // 20f(10) // 20f(undefined) // 20
Paràmetres rest
Section titled “Parà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 ...
:
function max(x: number, ...xs: number[]) { let result = x for (const x of xs) { if (x > result) result = x } return result}
console.log(max(10)) // 10console.log(max(10, 30, 15)) // 30
Variables de funció
Section titled “Variables de funció”A continuació pots veure com pots crear una funció anònima:
(function () { console.log("Hello") })
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.ts
Si vols, pots crear i executar la funció amb ()
:
(function () { console.log("Hello") }) () //
Ara, si executes el codi, es crea la funció anònima i s’executa:
> deno test.tsHello
Tanmateix, una funció anònima, també coneguda com a literal de funció, es pot assignar a una variable per crear una variable de funció:
const sayHi = function() { console.log("Hello") }
Això crea una variable de funció anomenada sayHi
.
En aquesta expressió, la funció literal original es troba a la part dreta del símbol =
:
const sayHi = function() { console.log("Hello") } ///////////////////////////////////
i el nou nom de la variable es troba al costat esquerre:
const sayHi = function() { console.log("Hello") } /////
Paràmetres
Section titled “Paràmetres”Una funció anònima és com qualsevol funció: pot prendre paràmetres i retorna valors
(function (a: number) { return a * 2 })
I es crida com qualsevol funció:
const result = (function (a: number) { return a * 2 }) (2)console.log(result) // 4
I la podem asignar a una variable:
const double = function (a: number) { return a * 2}
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í:
const double = function (a: number) { return a * 2}
const result = double(6)console.log(result) // 12
A més, quan tens altres funcions del tipus number => number
les pots emmagatzemar en una llista:
const fs = [ (function (a: number) { return a * 2}), (function (a: number) { return a * 3})]
for (const f of fs) { console.log(f(4))}
Si executes el codi, pots veure que s’executen totes les funcions de la llista:
> deno test.ts812
Un 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
Section titled “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:
function sayHi() { console.log("Hello")}
const sayHello = sayHi
sayHello() // HellosayHi() // Hello
El mateix es pot fer amb una variable de funció:
const sayHi = function() { console.log("Hello")}
const sayHello = sayHi// ...
TODO explicar inicialització
Funció d’ordre superior
Section titled “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ó
Section titled “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ó:
function sayHello(f: ()=> void) { f()}
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àmtrestring
coms
o un parametrenumber
comn
.- La signatura de tipus de
f
especifica el tipus de funcions que acceptarà aquest funció. - La part
()
de la signatura def
(a la part esquerra del símbol=>
) indica quef
no pren paràmetres d’entrada. - La part
void
de la signatura (a la part dreta del símbol=>
) indica quef
no 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
:
function helloDavid() { console.log("Hello, David")}
Com que les signatures de tipus coincideixen, pots passar helloDavid
a sayHello
:
function sayHello(f: () => void) { f()}
function helloDavid() { console.log("Hello, David")}
sayHello(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
:
function bonjourJuliet() { console.log("Bonjour, Juliet")}
> deno test.tsBonjour, Juliet
Sintaxis
Section titled “Sintaxis”En aquesta funció:
function sayHello(f: () => void) { f()}
Has observat que la signatura de tipus de f
és:
() => void
Saps 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: (a: number, b: number) => number
T’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:
function sum(a: number, b: number): number { return a + b}
function subtract(a: number, b: number): number { return a - b}
function multiply(a: number, b: number): number { return a * b}
La funció execute
accepta com a paràmetre qualsevol de les tres funcions:
function execute(f: (a: number, b: number) => number) { console.log(f(5, 8))}
// ...
execute(sum)execute(subtract)execute(multiply)
Pots veure que funciona:
> deno test.ts13-340
Prenent un paràmetre de funció juntament amb altres paràmetres
Section titled “Prenent 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
:
function executeNTimes(f: () => void, n: number) { let i = 0 while (i < n) { f() 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
:
function helloWord() { console.log("Hello, world")}
A continuació, passa aquesta funció a executeNTimes
juntament amb un number
:
executeNTimes(helloWord, 3)
Si executes el codi:
> deno test.tsHello, worldHello, worldHello, world
Excel·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:
function executeAndPrint(f: (a: number, b: number) => number, x: number, y: number) { const result = f(x, y) console.log(result)}
Com que les fucions sum
i multiply
coincideixen amb aquesta signatura de tipus, es poden passar a executeAndPrint
juntament amb dos valors number
:
function executeAndPrint(f: (a: number, b: number) => number, x: number, y: number) { const result = f(x, y) console.log(result)}
function sum(a: number, b: number): number { return a + b}
function multiply(a: number, b: number): number { return a * b}
executeAndPrint(sum, 3, 11) // prints 14executeAndPrint(multiply, 3, 9) // prints 27
Coherència de signatura del tipus de funció
Section titled “Coherè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:
const sum: (a: number, b: number) => number = function (a: number, b: number) { return a + b}
Aquest codi consta de la signatura de tipus:
const sum: (a: number, b: number) => number = function (a: number, b: number) { //////////////////////////////// return a + b}
Els paràmetres d’entrada:
const sum: (a: number, b: number) => number = function (a: number, b: number): number { ////////////////////////////// return a + b}
i el cos de la funció:
const sum: (a: number, b: number) => number = function (a: number, b: number) { return a + b /////}
La consistència de TypeScript es mostra aquí, on aquest tipus de funció:
const sum: (a: number, b: number) => number = function (a: number, b: number) { //////////////////////////////// return a + b}
és el mateix que la signatura de tipus que utilitzes per definir un paràmetre d’entrada de funció:
function executeAndPrint(f: (a: number, b: number) => number, x: number, y: number) { //////////////////////////////// const result = f(x, y) console.log(result)}
Funcions arrow
Section titled “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í:
const f = (arg1, arg2, ..., argN) => expression
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:
const f = function(arg1, arg2, ..., argN) { return expression}
Veamos un ejemplo concreto:
let sum = (a:number, b:number) => a + b
/* Esta función de flecha es una forma más corta de:let sum = function(a: number, b: number) { return a + b}*/
alert( sum(1, 2) ) // 3
Como 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:
let sayHi = () => alert("¡Hola!")
sayHi()
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:
let age = Number(prompt("What is your age?", "18"))
let welcome = (age < 18) ? () => alert('¡Hola!') : () => alert("¡Saludos!")
welcome()
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
Section titled “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:
let sum = (a: number, b: number) => { // la llave abre una función multilínea let result = a + b return result // si usamos llaves, entonces necesitamos un "return" explícito};
console.log(sum(1, 2)) // 3
Activitat
Section titled “Activitat”1. Implementa la funció map
, que retorna una llista en que ha aplicat f
a tots els elements de xs
:
function map(xs: number[], f: (x: number) => number): number[] { // TODO}
const result = map([2, 3, 4], a => a + 2)
console.log(result) // [ 4, 5, 6 ]
function map(xs: number[], f: (x: number) => number): number[] { const result = [] for (const x of xs) { result.push(f(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
:
function filter(xs: number[], f: (x: number) => boolean): number[] { // ...}
const result = filter([1, 2, 3, 4], a => a > 2)
console.log(result) // [ 3, 4]
function filter(xs: number[], f: (x: number) => boolean): number[] { const result = [] for (const x of xs) { if (f(x)) result.push(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
:
function reduce(xs: number[], initialValue: number, f: (result: number, x: number) => number): number { let result = initialValue for (const x of xs) { result = f(result, x) } return result}
const result = reduce([1, 5, 10], 0, (a, b) => a + b)
console.log(result) // 16
function reduce(xs: number[], initialValue: number, f: (result: number, x: number) => number): number { let result = initialValue for (const x of xs) { result = f(result, x) } return result}
4. Donada aquesta llista:
const xs = [1, -5, 10, 15, 20]
const result = // ...
console.log(result) // 12000
Amb 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.
let ys = filter(xs, x => x > 0)ys = map(ys, x => x > 10 ? x * 2 : x)const result = reduce(ys, 1, (a, b) => a * b)
O en una sola linea
const result = reduce(map(filter(xs, x => x > 0), x => x > 10 ? x * 2 : x), 1, (a, b) => a * b)
Crear una funció que retorna una funció
Section titled “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ó:
function greet() {}
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
:
function greet(): (s: 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ó:
(name: string) => console.log(`Hello, ${name}`)
Ara només has de tornar aquesta funció des de la funció:
function greet(): (s: string) => void { return (name: string) => console.log(`Hello, ${name} `)}
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ó:
const greetFunction = greet()
Ara pots invocar a greetFunction
:
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
:
function greet(theGreeting: string): (s: string) => void { return (name: string) => console.log(`${theGreeting}, ${name} `)}
Ara, quan invoques la teva funció, el procés és més flexible perquè pots canviar la salutació, tal com pots veure a continuació:
const sayHola = greet("Hola")
sayHola
és una funció que pren un paràmetre d’entrada de tipus string
i retorna void
(res).
const sayHola: (s: string) => void = greet("Hola")
Ara, quan invoques la funció sayHola
la sortida és diferent:
sayHola("Laura") // prints "Hello, Laura"
Pots crear tantes funcions diferent com vulguis:
const sayCiao = greet("Ciao")const sayBonjour = greet("Bonjour")
sayCiao("Laura") // prints "Ciao, Laura"
Activitat
Section titled “Activitat”1. A continuació tens un codi que genera una llista de llistes de números:
{ const xss: number[][] = Array.from({ length: 100 }, () => Array.from({ length: 100 }, () => Math.floor(Math.random() * 100000)))
console.log(xss)}
Escriu un codi que torni la llista en què la suma dels seus números és menor:
{ const xss: number[][] = Array.from({length: 100}, () => Array.from({length: 100}, () => Math.floor(Math.random() * 100000)))
const result = xss. map(xs => [xs.reduce((a, b) => a + b), xs]). reduce((acc, sum_xs) => sum_xs[0] > acc[0] ? sum_xs : acc)
console.log(result)}
El contingut d'aquest lloc web té llicència CC BY-NC-ND 4.0.
©2022-2025 xtec.dev