Come configurare smartphone e PC. Portale informativo
  • casa
  • Windows Phone
  • Javascript usando una funzione precedentemente dichiarata in un'altra. Funzioni

Javascript usando una funzione precedentemente dichiarata in un'altra. Funzioni

Articolo in sviluppo!

Un articolo in cui consideriamo cos'è una funzione, così come la versione tradizionale (classica) di lavorare con essa. Inoltre, analizzeremo quali sono gli argomenti (parametri) della funzione e l'istruzione di ritorno.

Che cos'è una funzione?

Una funzione è un po' set di istruzioni, che può essere nominato e poi rivolgersi a lui con questo nome da qualsiasi punto del programma.

Un classico esempio di utilizzo di una funzione. La pagina web contiene codice JavaScript, qualche frammento in cui si ripete più volte. Per evitare questo, puoi formatta questo frammento come una funzione, ma poi chiamalo nei punti giusti del codice dal nome di questa funzione. Chiamando questa funzione significherà esecuzione delle istruzioni situato in esso.

Come organizzare l'esecuzione di alcune attività in JavaScript usando le funzioni? Per fare ciò, di solito fai qualcosa del genere:

  • suddividere l'attività in parti componenti (attività secondarie);
  • i sottocompiti sono formalizzati tramite funzioni;
  • sviluppare il codice principale utilizzando la chiamata delle funzioni create.

Di conseguenza, un tale programma diventa più strutturato. È più facile apportare varie modifiche e aggiungere nuove funzionalità.

Dichiarazione e chiamata di una funzione

Le operazioni sulle funzioni in JavaScript possono essere suddivise in 2 passaggi:

  • annuncio (creazione) funzioni.
  • chiamata (esecuzione) questa funzione.

Dichiarazione di funzione. La creazione di una funzione in JavaScript inizia scrivendo la parola chiave della funzione, seguita dal nome della funzione, seguito da una x tra parentesi, se necessario. i parametri sono elencati, seguito da istruzioni che racchiuso tra parentesi graffe.

// dichiarazione di funzione someName function someName() ( alert("Hai chiamato la funzione someName!"); ) JavaScript - Sintassi di dichiarazione di funzione

Vengono chiamate funzioni di questo tipo in JavaScript dichiarazione di dichiarazione di funzione. Oltre a questo tipo, JavaScript distingue anche tra le funzioni espressione di definizione della funzione ed espressione della funzione freccia.

La composizione del nome della funzione segue le stesse regole del nome della variabile. Quelli. può contenere lettere, numeri (0-9), segni "$" e "_". Si consiglia di utilizzare solo lettere dell'alfabeto inglese (a-z, A-Z) come lettere. Un nome di funzione, come un nome di variabile, non può iniziare con un numero.

Una funzione può avere un numero qualsiasi di parametri o nessuno. Le parentesi sono comunque incluse. Se sono presenti più parametri, è necessario separarli l'uno dall'altro utilizzando una virgola. I parametri di funzione sono accessibili tramite il loro nome.

Set di istruzioni, racchiuso tra parentesi graffe, è il codice funzione che verrà eseguito quando viene chiamato.

Chiamata di funzione. Funzione dichiarata da sola non verrà eseguito. Per eseguirlo, deve essere chiamato. Una funzione viene chiamata specificandone il nome e due parentesi. Gli argomenti sono riportati tra parentesi, se necessario.

// chiama la funzione data nell'esempio precedente someName(); JavaScript - Sintassi della chiamata di funzione

Una funzione in JavaScript è un oggetto?

Le funzioni in JavaScript sono oggetti. Tutto in JavaScript è un oggetto tranne i sei tipi di dati primitivi. E se la funzione è un oggetto, allora un riferimento ad essa può essere memorizzato in una variabile.

// dichiarazione di funzione someName function someName() ( alert("Hai chiamato la funzione someName!"); ) var reference = someName;

Successivamente, puoi chiamare la funzione in questo modo:

Riferimento();

Parametri e argomenti di funzione

Argomenti di funzione sono i valori che vengono passati alla funzione nella fase della sua chiamata. Gli argomenti sono separati l'uno dall'altro con una virgola.

// chiamando la funzione sayWelcome con due argomenti passati ad essa sayWelcome("Ivan", "Ivanov"); // un'altra chiamata alla funzione sayWelcome con due argomenti sayWelcome("Peter", "Petrov");

Parametri di funzioneè un modo in JavaScript per fare riferimento ad argomenti all'interno di una funzione. I parametri della funzione sono descritti nella fase della sua dichiarazione tra parentesi.

In altre parole parametri di funzione sono variabili locali che vengono create automaticamente in fase di avvio della funzione. Come valori, i parametri ricevono gli argomenti corrispondenti passati alla funzione durante la sua chiamata. È possibile accedere ai parametri solo all'interno di questa funzione, al di fuori di essa non esistono.

// dichiarazione della funzione sayWelcome, che ha due parametri funzione sayWelcome (userFirstName, userLastName) ( // istruzione che mostra i valori dei parametri "userFirstName" e "userLastName" alla console console.log("Benvenuto, " + userLastName + " " + userFirstName ); )

In JavaScript, quando si chiama una funzione il numero di argomenti non deve essere uguale al numero di parametri. I parametri che non erano impostati su un valore al momento della chiamata non saranno definiti.

Ad esempio, chiamiamo la funzione dall'esempio sopra, senza specificare uno e due parametri:

// chiamando la funzione sayWelcome e passandogli un argomento sayWelcome("Peter"); // Benvenuto, Peter non definito // chiama la funzione sayWelcome senza passare argomenti ad essa sayWelcome(); // Benvenuto undefined undefined

Un esempio di una funzione che visualizzerà semplicemente gli argomenti passati ad essa nella console del browser:

// dichiarazione della funzione function outputParam(param1, param2, param3) ( console.log(param1 + "; " + param2 + "; " + param3); ) // chiama la funzione outputParam passandole un numero diverso di parametri outputParam(" Pioggia", "Neve", "Nebbia"); // Piovere; Neve; mist outputParam(17); // 17; non definito; outputParam(24,33) non definito; // 24; 33; outputParam(); // non definito; non definito; non definito

Un altro modo per fare riferimento agli argomenti all'interno di una funzione consiste nell'utilizzare l'oggetto argomenti speciali. L'accesso agli argomenti tramite argomenti viene eseguito allo stesso modo degli elementi di un array regolare, ad es. dai loro numeri di serie. Pertanto, argomento - ti consentirà di ottenere il primo argomento, argomenti - il secondo argomento e così via.

// dichiarazione di funzione sum function sum(num1, num2) ( /* num1 o argomenti - ottiene il valore di 1 argomento num2 o argomenti - ottiene il valore di 2 argomenti */ var sum1 = num1 + num2, sum2 = argomenti + argomenti; return "Sum, ottenuto con il metodo 1 è " + sum1 + "; sum ottenuto con il metodo 2 è " + sum2; ) /* stampa il risultato della funzione sum alla console 7 - il primo argomento (accessibile sia da nome num1 e per argomenti) 4 - il secondo argomento (accessibile sia con il nome num2 che per argomenti) */ console.log(sum(7,4));

La principale differenza tra questi metodi è che il primo consente di fare riferimento solo a quegli argomenti a cui sono stati dati dei nomi nella fase di dichiarazione della funzione. Il secondo metodo consente di ottenere il valore di qualsiasi argomento, anche se non ha un nome (per numero di serie). Questa caratteristica del linguaggio JavaScript consente di creare funzioni flessibili universali.

Oltre a ricevere argomenti, l'oggetto argomenti consente anche di scoprirne il numero. Questo viene fatto usando la proprietà length.

Iterare sugli argomenti passato a una funzione, ad esempio, usando un ciclo for o for...of.

// dichiarazione della funzione sum function sum() ( var i = 0; console.log("Emetti tutti gli argomenti usando il ciclo for"); for (i; i< arguments.length; i++) { console.log(i + 1 + " аргумент равен " + arguments[i]); } console.log("Вывод всех аргументов с помощью цикла for...of"); for (arg of arguments) { console.log(arg); } } // вызов функции sum sum(7, 4, 3, 1);

Una funzione che stampa sulla console tutti gli argomenti passati ad essa e il loro numero:

// funzione di dichiarazione di funzione myFunction() ( var i; console.log("Numero di parametri passati = " + arguments.length); // itera su tutti i parametri usando il ciclo for for (i = 0; i< arguments.length; i++) { console.log(i + " параметр = " + arguments[i]); } } // вызовы функции myFunction myFunction(3, 7, 27, "JavaScript"); myFunction(); myFunction("Яблоки", "Груши", "Апельсины");

Una funzione che esegue l'addizione di tutti gli argomenti passati (il loro numero non è noto in anticipo):

// dichiarazione di funzione var myCalc = function() ( // itera su tutti i parametri usando il ciclo for var i, sum = 0; for (i = 0; i lt; arguments.length; i++) ( sum += argomenti[i ] ; ) // restituisce la somma come risultato restituisce sum; ) // chiamata di funzione (output sulla console) console.log(myCalc(4, 20, 17, -6));

Di conseguenza, l'oggetto arguments può essere implementato nel corpo della funzione:

  • controllare il numero di argomenti passati;
  • elaborare un numero qualsiasi di parametri.

Oltre alla funzione stessa, anche altre funzioni in essa contenute hanno accesso agli argomenti che le vengono passati durante la fase di chiamata.

Funzione mainF(p1, p2) ( funzione childF() ( console.log("p1 = " + p1 + "; p2 = " + p2); ) childF(); ) mainF(3, 5); // p1 = 3; p2 = 5 principaleF(4, 7); // p1 = 4; p2 = 7

Valore predefinito del parametro

A partire da ECMAScript 2015 (6) parametro di funzione puoi impostare il valore che avrà per impostazione predefinita.

Ad esempio, impostiamo il parametro "color" sul valore predefinito di "#009688":

Funzione setBGColor(color = "#009688") ( document.body.style.backgroundColor = colore; ) setBGColor(); // il colore di sfondo sarà #009688 setBGColor("red"); // il colore di sfondo sarà rosso

Prima di ECMAScript 2015, era possibile impostare un parametro su un valore predefinito, ad esempio, era così:

Funzione setBGColor(color) ( color = color !== undefined ? color: "#009688"; // imposta il colore sul valore predefinito di "#009688" document.body.style.backgroundColor = color; )

Parametri rimanenti

Se, quando chiami una funzione, le passi più argomenti di quanti ne abbia parametri, puoi ottenere quelli rimanenti usando il cosiddetto parametri rimanenti (patametri di riposo). Questa funzione è apparsa nel linguaggio da ECMAScript 2015.

// ...nums sono i parametri rimanenti, a cui è possibile accedere in questo caso per nome nums function doMath(mathAction, ...nums) ( var result = 0; nums.forEach(function(value) ( ​​switch ( mathAction) ( case "sum": risultato += valore; break; case "sumCube": risultato += valore**3; break; case "sumSquare": risultato += valore**2; break; deafult: risultato = 0 ; ) ) ) restituisce il risultato; ) console.log(doMath("sum", 3, 4, 21, -4)); // 24 (3 + 4 + 21 + (-4)) console.log(doMath("sumSquare", 1, 4)); // 17 (1^2 + 4^2) console.log(doMath("sumCube", 3, 2, 4)); // 99 (3^3 + 2^3 + 4^3)

dichiarazione di ritorno

L'istruzione return ha lo scopo di restituire il valore o il risultato della valutazione dell'espressione della funzione corrente. Il valore o l'espressione deve essere separato da return da uno spazio. Inoltre, l'istruzione return termina l'esecuzione della funzione, ad es. tutte le istruzioni successive non verranno eseguite.

Una funzione in JavaScript restituisce sempre un risultato, indipendentemente dal fatto che l'istruzione return venga utilizzata o meno.

// funzione funzione di ritorno sayWelcome (userFirstName, userLastName) ( if ((!userFirstName) || (!userLastName)) return "Benvenuto, utente anonimo"; else return "Benvenuto, " + userLastName + " " + userFirstName ; ) // dichiarazione variabile persona var persona; // Assegna il risultato della funzione sayWelcome alla variabile person person = sayWelcome("Ivan","Ivanov"); // stampa il valore della variabile sulla console console.log(person); //Istruzione che trasmetterà alla console il risultato della funzione sayWelcome console.log(sayWelcome("Peter","Petrov")); //Istruzione che invierà alla console il risultato della funzione sayWelcome console.log(sayWelcome("Sidorov")); JavaScript - Funzione con convalida dei parametri

Una funzione in JavaScript restituisce sempre un risultato come risultato della sua esecuzione, anche se non è stata definita in modo esplicito utilizzando l'istruzione return. Questo risultato è indefinito.

// 1. una funzione che non restituisce alcun risultato funzione sayWelcome (userFirstName, userLastName) ( console.log("Benvenuto, " + userLastName + " " + userFirstName); ) // prova a ottenere il risultato da una funzione che lo fa non restituisce nulla console .log(sayWelcome ("Ivan", "Ivanov")); // 2. funzione contenente un'istruzione return senza una funzione valore sayDay (day) ( day = "Today, " + day; return; //questa istruzione non verrà eseguita perché segue l'istruzione return console.log(day) ; ) // prova a ottenere il risultato della funzione che contiene l'istruzione return senza un valore console.log(sayDay("February 21, 2016")); JavaScript - Ottieni valore da una funzione che non restituisce nulla

Lo stesso risultato si otterrà se non viene specificato un valore di ritorno per l'istruzione di ritorno.

Sovraccarico di funzioni in JavaScript

L'overloading delle funzioni nella programmazione è la capacità di dichiarare più funzioni con lo stesso nome nello stesso ambito. Tali funzioni differiscono tra loro per tipo e numero di argomenti. Ogni funzione ha una propria logica di programmazione. L'overloading delle funzioni viene utilizzato in modo che sia possibile eseguire azioni simili utilizzando lo stesso nome di funzione.

Il linguaggio JavaScript non supporta l'overloading delle funzioni nel modo in cui è implementato, ad esempio, in linguaggi simili al C. Quelli. in JavaScript, non è possibile creare più funzioni con lo stesso nome che si trovano nello stesso ambito.

Funzionalità simili possono essere implementate in JavaScript utilizzando i seguenti passaggi:

  • Per verificare se un argomento è stato passato o meno, utilizzare una condizione controllandone il valore per undefined .
  • Per controllare il numero di argomenti passati a una funzione, utilizzare la proprietà della lunghezza degli argomenti dell'oggetto.
  • Per scoprire il tipo del valore dell'argomento passato, utilizzare gli operatori typeof o instanceof.
  • Per lavorare con un numero variabile di argomenti, utilizzare l'oggetto argomenti.
  • A partire da ECMAScript6, puoi specificare i valori predefiniti per gli argomenti.

Ad esempio, creiamo una funzione che può essere chiamata con uno o due argomenti:

//dichiarando una funzione che cambia il colore di sfondo degli elementi function setBgColor(bgColor,elements) ( //se il parametro elements non è specificato quando si chiama if (elements=== undefined) ( //quindi imposta il suo valore su "div" elements = "div "; ) // recupera tutti gli elementi elements = $(elementi); // scorre tutti gli elementi e impostali sugli elementi del colore di sfondo specificati. each(function()( $(this).css("background -color",bgColor) ; )); ) /*Richiama la funzione setBgColor con un parametro. Perché 2 parametro non è specificato, quindi questa funzione cambierà il colore di sfondo di tutti gli elementi div.*/ setBgColor("green"); /*Richiama la funzione setBgColor con 2 parametri. Perché 2 è impostato, quindi questa funzione cambierà il colore di sfondo solo degli elementi del pulsante.*/ setBgColor("#ff0000","button");

Apportiamo alcune modifiche al codice sopra. Vale a dire, specifichiamo il valore predefinito per il secondo parametro:

//dichiarando una funzione che cambia il colore di sfondo degli elementi //il parametro elements è impostato su "div" per impostazione predefinita function setBgColor(bgColor,elements = "div") ( //get all elements elements = $(elements); / /itera tutti gli elementi e imposta il colore di sfondo specificato su di essi elements.each(function()( $(this).css("background-color",bgColor); )); ) //chiama la funzione setBgColor, specificando un parametro setBgColor("verde"); //chiama la funzione setBgColor, specificando 2 parametri setBgColor("#ff0000","button");

Un esempio di come implementare una funzione "sovraccarico" in JavaScript che calcola il numero di calorie di cui una persona ha bisogno al giorno:

// descrizione della funzione function countCal(sex, height) ( // parametri: sex (sesso) e height (height) var result; if ((sex === 0) || (sex === "man")) ( risultato = (altezza - 100) * 20; ) else if ((sesso === 1) || (sesso === "donna")) ( risultato = (altezza - 105) * 19; ) if (risultato) ( // argomenti - livello di attività if (argomenti) ( risultato *= argomenti; ) console.log("Numero di calorie per la vita normale: " + risultato); ) else ( console.log("Parametri non validi"); ) ) / * chiamando la funzione e passandole 2 argomenti (1 - "man", accessibile con il nome sex e argomenti; 2 - il valore 185, accessibile con il nome sex e argomenti) */countCal("man", 185); /* chiamando la funzione e passandole 3 parametri, anche se solo 2 sono presenti nella descrizione della funzione (in questo caso, puoi ottenere il valore di 3 parametri solo come argomenti) */ countCal(0, 185, 2);

ricorsione

La ricorsione è una chiamata all'interno del corpo di una funzione a se stessa.

Una chiamata di funzione viene solitamente effettuata a seconda del modo in cui viene dichiarata per nome o tramite una variabile contenente un riferimento a questa funzione.

Funzione fact(n) ( if (n === 1) ( return 1; ) return fact(n-1) * n; ) console.log(fact(5)); // 120

Puoi chiamare una funzione all'interno del suo corpo non solo per nome, ma anche usando la proprietà chiamata dell'oggetto arguments. Ma è meglio non usare questa proprietà, perché. è obsoleto. A parte questo, non funziona affatto in modalità rigorosa.

Cosa sono le funzioni integrate (standard)?

JavaScript ha una vasta gamma di funzioni integrate (standard). Queste funzioni sono già descritte nel motore del browser stesso. Quasi tutti sono metodi dell'uno o dell'altro oggetto.

Ad esempio, per chiamare l'avviso di funzione (metodo) incorporata, non è necessario dichiararlo in anticipo. È già descritto nel browser. Il metodo alert viene chiamato specificando un nome, parentesi e un argomento al loro interno. Questo metodo è progettato per visualizzare un messaggio sullo schermo sotto forma di finestra di dialogo. Il messaggio di testo è preso dal valore del parametro di questa funzione.

// chiama la funzione alert alert("Some text"); JavaScript - Chiamare la funzione di avviso

Le funzioni sono un concetto chiave in JavaScript. La caratteristica più importante del linguaggio è il supporto delle funzioni di prima classe (funziona come cittadino di prima classe). Qualsiasi la funzione è un oggetto, e quindi può essere manipolato come un oggetto, in particolare:

  • passare come argomento e restituire come risultato quando si chiamano altre funzioni (funzioni di ordine superiore);
  • creare in modo anonimo e assegnare come valori a variabili o proprietà di oggetti.

Ciò determina l'elevata potenza espressiva di JavaScript e gli consente di essere classificato come un linguaggio che implementa il paradigma della programmazione funzionale (che di per sé è molto interessante per molte ragioni).

Funzione in JavaScript un particolare tipo di oggetti che permette di formalizzare determinate logiche di comportamento e di elaborazione dati tramite il linguaggio.

Per capire come funzionano le funzioni è necessario (e sufficiente?) avere un'idea dei seguenti punti:

Dichiarazione di funzione

Funzioni della forma "istruzione di dichiarazione di funzione"

Dichiarazione di funzione ( definizione della funzione, o dichiarazione di funzione, o istruzione di funzione) è costituito dalla parola chiave function e dalle parti seguenti:

  • Nome della funzione.
  • Un elenco di parametri (presi dalla funzione) racchiusi tra parentesi () e separati da virgole.
  • Le istruzioni che verranno eseguite dopo una chiamata di funzione sono racchiuse tra parentesi graffe ( ).

Ad esempio, il codice seguente dichiara una semplice funzione denominata square:

funzione quadrato(numero) ( numero restituito * numero; )

La funzione quadrato accetta un parametro, denominato numero. Consiste in un'istruzione, che significa restituire il parametro di questa funzione (è un numero) moltiplicato per se stesso. L'istruzione return specifica il valore che verrà restituito dalla funzione.

numero di ritorno * numero;

I parametri primitivi (come un numero) vengono passati alla funzione in base al valore; significato viene passato alla funzione, ma se la funzione cambia il valore del parametro, questa modifica non si rifletterà globalmente o dopo la chiamata di funzione.

Se si passa un oggetto come parametro (non una primitiva, ad esempio, o oggetti definiti dall'utente) e la funzione modifica una proprietà dell'oggetto passato ad essa, tale modifica sarà visibile all'esterno della funzione, come mostrato nell'esempio seguente :

Funzione myFunc(theObject) ( theObject.make = "Toyota"; ) var mycar = (marca: "Honda", modello: "Accord", anno: 1998); var x, y; x = mycar.make; // x ottiene il valore "Honda" myFunc(mycar); y=miaauto.make; // y è impostato su "Toyota" // (la proprietà è stata modificata dalla funzione)

Funzioni della forma "espressione di definizione di funzione"

Una funzione della forma "istruzione di dichiarazione di funzione" è, nella sintassi, un'istruzione ( dichiarazione), un'altra funzione può essere nella forma "espressione di definizione di funzione". Tale funzione può essere anonimo(lei non ha un nome). Ad esempio, la funzione quadrato può essere chiamata in questo modo:

Var quadrato = funzione(numero) (restituisce numero * numero; ); var x = quadrato(4); // x ottiene il valore 16

Tuttavia, il nome può anche essere assegnato per chiamare se stesso all'interno della funzione stessa e per il debugger ( debugger) per identificare la funzione nelle tracce dello stack ( impilare le tracce; "traccia" - "traccia" / "impronta").

Var fattoriale = funzione fac(n) ( ritorno n< 2 ? 1: n * fac(n - 1); }; console.log(factorial(3));

Le funzioni della forma "espressione di definizione di funzione" sono utili quando una funzione viene passata come argomento a un'altra funzione. L'esempio seguente mostra una funzione di mappa che dovrebbe accettare una funzione come primo argomento e una matrice come secondo.

Function map(f, a) ( var result = , // Crea un nuovo Array i; for (i = 0; i != a.length; i++) result[i] = f(a[i]); restituisce il risultato ; )

Nel codice seguente, la nostra funzione prende una funzione che è un'espressione di definizione di funzione e la esegue per ogni elemento dell'array ricevuto come secondo argomento.

Function map(f, a) ( var result = ; // Crea un nuovo Array var i; // Dichiara variabile per (i = 0; i != a.length; i++) result[i] = f(a[i ]); restituisce il risultato; ) var f = funzione(x) (restituisce x * x * x; ) var numeri = ; var cubo = mappa(f,numeri); registro della console (cubo);

La funzione restituisce: .

In JavaScript, una funzione può essere dichiarata con una condizione. Ad esempio, la seguente funzione verrà assegnata a myFunc solo se num è 0:

Var myFunc; if (num === 0) ( myFunc = function(theObject) ( theObject.make = "Toyota"; ) )

Oltre alle dichiarazioni di funzione qui descritte, puoi anche utilizzare il costruttore Function per creare funzioni da una stringa in fase di esecuzione ( tempo di esecuzione), piace .

Metodoè una funzione che è una proprietà di un oggetto. Puoi saperne di più su oggetti e metodi al link: Lavorare con gli oggetti.

Chiamate di funzione

La dichiarazione di funzione non la esegue. Una dichiarazione di funzione nomina semplicemente la funzione e specifica cosa fare quando la funzione viene chiamata. Chiamata La funzione esegue effettivamente le azioni specificate con i parametri specificati. Ad esempio, se definisci una funzione quadrata, puoi chiamarla in questo modo:

quadrato(5);

Questa istruzione chiama la funzione con l'argomento 5. La funzione chiama le sue istruzioni e restituisce il valore 25.

Le funzioni possono rientrare nell'ambito quando sono già definite, ma le funzioni del modulo "istruzione di dichiarazione di funzione" possono essere revocate ( alzando - sollevamento), proprio come in questo esempio:

Console.log(quadrato(5)); /* ... */ funzione quadrato(n) ( ritorno n * n; )

L'ambito di una funzione è la funzione in cui è definita, o l'intero programma se è dichiarato a un livello superiore.

Nota: Funziona solo quando la dichiarazione della funzione utilizza la sintassi sopra (cioè la funzione funcName()()). Il codice seguente non funzionerà. Ciò significa che il sollevamento di funzioni funziona solo con la dichiarazione di funzione e non con l'espressione di funzione.

Console.log(quadrato); // il quadrato viene sollevato con un valore indefinito. console.log(square(5)); // TypeError: square non è una funzione var square = function(n) ( return n * n; )

Gli argomenti delle funzioni non sono limitati a stringhe e numeri. Puoi passare interi oggetti a una funzione. La funzione show_props() (dichiarata in Lavorare con gli oggetti) è un esempio di una funzione che accetta oggetti come argomento.

Una funzione può chiamare se stessa. Ad esempio, ecco una funzione fattoriale ricorsiva:

Funzione fattoriale(n) ( if ((n === 0) || (n === 1)) restituisce 1; else restituisce (n * fattoriale(n - 1)); )

Quindi puoi calcolare i fattoriali da uno a cinque in questo modo:

Var a, b, c, d, e; a = fattoriale(1); // a ottiene il valore 1 b = fattoriale(2); // b ottiene il valore 2 c = fattoriale(3); // c ottiene il valore 6 d = fattoriale(4); // d ottiene il valore 24 e = fattoriale(5); // e ottiene il valore 120

Esistono altri modi per chiamare una funzione. Ci sono casi frequenti in cui le funzioni devono essere chiamate dinamicamente, i numeri degli argomenti delle funzioni devono essere modificati o una funzione deve essere chiamata con un contesto specifico. Si scopre che le funzioni stesse sono oggetti e quegli oggetti a loro volta hanno metodi (vedi oggetto). Uno di questi è un metodo, il cui uso può raggiungere questo obiettivo.

Ambito della funzione

(ambito della funzione)

Non è possibile accedere alle variabili dichiarate in una funzione al di fuori di tale funzione, quindi le variabili (che sono necessarie specificamente per la funzione) vengono dichiarate solo nell'ambito della funzione. In questo caso, la funzione ha accesso a tutte le variabili e funzioni dichiarate all'interno del suo scope. In altre parole, una funzione dichiarata nell'ambito globale ha accesso a tutte le variabili nell'ambito globale. Una funzione dichiarata all'interno di un'altra funzione ha comunque accesso a tutte le variabili della sua funzione padre e ad altre variabili a cui questa funzione padre ha accesso.

// Le seguenti variabili sono dichiarate nell'ambito globale var num1 = 20, num2 = 3, name = "Chamahk"; // Questa funzione è dichiarata nella funzione di ambito globale multiply() ( return num1 * num2; ) multiply(); // restituisce 60 // Esempio di funzione annidata function getScore() ( var num1 = 2, num2 = 3; function add() ( return name + " score" + (num1 + num2); ) return add(); ) getScore( ); // restituisce "Chamahk ha segnato 5"

Funzioni di ambito e stack

(stack di funzioni)

ricorsione

Una funzione può chiamare se stessa. Tre modi per chiamarlo:

  1. per nome della funzione
  2. da una variabile che fa riferimento a una funzione

Si consideri ad esempio la seguente funzione:

Var foo = function bar() ( // le istruzioni vanno qui );

All'interno della funzione ( corpo funzionale) i seguenti inviti sono tutti equivalenti:

  1. sbarra()
  2. argomenti.callee()
  3. pippo()

Viene chiamata una funzione che chiama se stessa funzione ricorsiva (funzione ricorsiva). Si scopre che la ricorsione è simile a un ciclo ( ciclo continuo). Entrambi chiamano un codice più volte ed entrambi richiedono una condizione (per evitare un ciclo infinito, o meglio una ricorsione infinita). Ad esempio, il seguente ciclo:

Varia x = 0; mentre (x< 10) { // "x < 10" - это условие для цикла // do stuff x++; }

potrebbe essere cambiato in una funzione ricorsiva e chiamando questa funzione:

Funzione loop(x) ( if (x >= 10) // "x >= 10" è la condizione finale (uguale a "!(x< 10)") return; // делать что-то loop(x + 1); // рекурсионный вызов } loop(0);

Tuttavia, alcuni algoritmi non possono essere semplici cicli ripetuti. Ad esempio, ottenere tutti gli elementi di una struttura ad albero (ad esempio, ) è implementato più facilmente usando la ricorsione:

Funzione walkTree(node) ( if (node ​​== null) // return; // fai qualcosa con gli elementi per (var i = 0; i< node.childNodes.length; i++) { walkTree(node.childNodes[i]); } }

Rispetto alla funzione loop, ogni chiamata ricorsiva stessa provoca molte chiamate ricorsive.

È anche possibile rendere non ricorsivi alcuni algoritmi ricorsivi, ma spesso la loro logica è molto complessa e richiederebbe l'uso di uno stack ( pila). In effetti, la ricorsione utilizza stach: function stack.

Il comportamento dello stack può essere visto nel seguente esempio:

Funzione foo(i) ( se (i< 0) return; console.log("begin: " + i); foo(i - 1); console.log("end: " + i); } foo(3); // Output: // begin: 3 // begin: 2 // begin: 1 // begin: 0 // end: 0 // end: 1 // end: 2 // end: 3

Funzioni e chiusure annidate

Puoi annidare una funzione all'interno di un'altra. funzione annidata ( funzione nidificata;interno) privato ( privato) e viene inserito in un'altra funzione ( esterno). Ecco come si forma chiusura (chiusura). Una chiusura è un'espressione (di solito una funzione) che può avere variabili libere insieme a un ambiente che lega quelle variabili (che "chiude" ( chiudere) espressione).

Poiché una funzione nidificata è una chiusura, ciò significa che una funzione nidificata può "ereditare" ( ereditare) argomenti e variabili della funzione in cui è annidato. In altre parole, la funzione nidificata contiene l'ambito della funzione esterna ( "esterno") funzioni.

Riassumere:

  • La funzione annidata ha accesso a tutte le istruzioni della funzione esterna.
  • Una funzione nidificata costituisce una chiusura: può utilizzare gli argomenti e le variabili della funzione esterna, mentre la funzione esterna non può utilizzare gli argomenti e le variabili della funzione nidificata.

L'esempio seguente mostra una funzione nidificata:

Funzione addSquares(a, b) ( funzione square(x) ( return x * x; ) return square(a) + square(b); ) a = addSquares(2, 3); // restituisce 13 b = addSquares(3, 4); // restituisce 25 c = addSquares(4, 5); // restituisce 41

Poiché la funzione nidificata forma una chiusura, è possibile chiamare la funzione esterna e fornire argomenti per entrambe le funzioni (per esterno e interno).

Funzione outside(x) ( funzione inside(y) ( return x + y; ) return inside; ) fn_inside = outside(3); // Pensaci: dammi una funzione per // passare 3 result = fn_inside(5); // restituisce 8 risultato1 = esterno(3)(5); // restituisce 8

Salvataggio di variabili

Si noti che il valore di x è stato mantenuto quando è stato restituito inside. La chiusura deve preservare argomenti e variabili in tutto l'ambito. Poiché ogni chiamata fornisce argomenti potenzialmente diversi, viene creata una nuova chiusura per ogni chiamata all'esterno. La memoria può essere cancellata solo quando l'interno è già rientrato e non è più disponibile.

Questo non è diverso dalla memorizzazione di riferimenti in altri oggetti, ma spesso è meno ovvio perché i riferimenti non sono impostati direttamente e non possono essere cercati lì.

Più livelli di nidificazione delle funzioni (funzioni nidificate multiple)

Le funzioni possono essere inserite più volte, ad es. la funzione (A) memorizza la funzione (B) che memorizza la funzione (C) in se stessa. Entrambe le funzioni B e C formano chiusure, quindi B ha accesso alle variabili e agli argomenti di A e C ha lo stesso accesso a B. Inoltre, poiché C ha accesso a B che ha lo stesso accesso ad A, anche C ha tale lo stesso accesso ad A. Pertanto, i cloures possono memorizzare diversi ambiti; memorizzano ricorsivamente l'ambito delle funzioni che lo contengono. È chiamato concatenamento (catena - catena; Perché si chiama "concatenamento" verrà spiegato più avanti)

Considera il seguente esempio:

Funzione A(x) ( funzione B(y) ( funzione C(z) ( console. log(x + y + z); ) C(3); ) B(2); ) A(1); // la console visualizzerà 6 (1 + 2 + 3)

In questo esempio, C ha accesso a y della funzione B e x della funzione A . Questo accade perché:

  1. La funzione B forma una chiusura che include A , cioè B ha accesso agli argomenti e alle variabili della funzione A.
  2. La funzione C forma una chiusura che include B .
  3. Poiché la chiusura della funzione B include A , la chiusura C include anche A, C ha accesso agli argomenti e alle variabili di entrambe le funzioni B e UN. In altre parole, C connette catena (catena) ambiti delle funzioni B e A, in quest'ordine.

Il contrario, tuttavia, non è vero. A non ha accesso alle variabili e agli argomenti di C perché A non ha tale accesso a B. Quindi C rimane privato solo a B .

Conflitti di nomi

Quando due argomenti o variabili nell'ambito di una chiusura hanno lo stesso nome, conflitto di nomi (conflitto di nomi). Più annidato ( più interiore) l'ambito ha la precedenza, quindi l'ambito nidificato ha la precedenza più alta e viceversa. Questa è una catena di ambiti ( catena di portata). Il primo collegamento è l'ambito più profondo e viceversa. Considera quanto segue:

Funzione outside() ( var x = 5; funzione inside(x) ( return x * 2; ) return inside; ) outside()(10); // restituisce 20 invece di 10

Si è verificato un conflitto di nomi nell'istruzione return x * 2 tra il parametro x della funzione interna e la variabile x della funzione esterna. La catena dell'ambito qui sarà così: ( dentro ==> fuori ==> oggetto globale ( oggetto globale)). Pertanto, x inside ha la precedenza su outside e otteniamo 20 (= 10 * 2) invece di 10 (= 5 * 2).

Chiusure

(Chiusure)

Le chiusure sono una delle caratteristiche principali di JavaScript. JavaScript consente l'annidamento delle funzioni e fornisce alla funzione annidata pieno accesso a tutte le variabili e funzioni dichiarate all'interno della funzione esterna (e ad altre variabili e funzioni a cui la funzione esterna ha accesso).

Tuttavia, la funzione esterna non ha accesso alle variabili e alle funzioni dichiarate nella funzione interna. Ciò fornisce una sorta di incapsulamento per le variabili all'interno di una funzione nidificata.

Inoltre, poiché la funzione nidificata ha accesso all'ambito della funzione esterna, le variabili e le funzioni dichiarate nella funzione esterna continueranno ad esistere dopo la sua esecuzione per la funzione nidificata, se l'accesso è mantenuto su di esse e su di essa (il che significa che il le variabili dichiarate nelle funzioni esterne vengono mantenute solo se la funzione interna le chiama).

La chiusura viene creata quando la funzione nidificata diventa in qualche modo disponibile in un ambito esterno alla funzione esterna.

Var pet = function(name) ( // La funzione esterna ha dichiarato la variabile "name" var getName = function() ( nome restituito; // La funzione nidificata ha accesso al "nome" della funzione esterna ) return getName; / / Restituisce la funzione nidificata, mantenendo così l'accesso // ad essa per un altro scopo ) myPet = pet("Vivie"); il mio animale domestico(); // Restituisce "Vivie", // perché anche dopo aver eseguito la funzione esterna // il nome viene mantenuto per la funzione nidificata

Un esempio più complesso è mostrato di seguito. È possibile restituire un oggetto con metodi per manipolare una funzione nidificata mediante una funzione esterna ( Restituzione).

Var createPet = function(name) ( var sex; return ( setName: function(newName) ( name = newName; ), getName: function() ( return name; ), getSex: function() ( return sex; ), setSex: function(newSex) ( if(typeof newSex === "string" && (newSex.toLowerCase() === "maschio" || newSex.toLowerCase() === "female")) ( sex = newSex; ) ) ) ) var pet = createPet("Vivie"); pet.getName(); // Vivie pet.setName("Oliver"); pet.setSex("maschio"); pet.getSex(); // maschio pet.getName(); // Oliver

Nel codice sopra, la variabile name della funzione esterna è accessibile alla funzione nidificata e non c'è altro modo per accedere alle variabili nidificate se non attraverso la funzione nidificata. Le variabili nidificate di una funzione nidificata sono archivi sicuri per argomenti e variabili esterni. Contengono dati "costanti" e "incapsulati" con cui lavorare con le funzioni nidificate. Le funzioni non devono nemmeno essere assegnate a una variabile o avere un nome.

Var getCode = (function() ( var apiCode = "0]Eal(eh&2"; // Un codice che non vogliamo che gli estranei possano modificare... return function() ( return apiCode; ); )()) ; getCode(); // Restituisce apiCode

Tuttavia, ci sono una serie di insidie ​​da tenere presente quando si utilizzano le chiusure. Se una funzione privata definisce una variabile con lo stesso nome del nome della variabile nell'ambito esterno, non è possibile fare nuovamente riferimento alla variabile nell'ambito esterno.

Var createPet = function(name) ( // La funzione esterna definisce una variabile chiamata "name". return ( setName: function(name) ( // La funzione inclusa definisce anche una variabile chiamata "name". name = name; // Come accediamo al "nome" definito dalla funzione esterna? ) ) )

Utilizzo dell'oggetto argomenti

L'oggetto arguments della funzione è uno pseudo-array. All'interno di una funzione, puoi fare riferimento ad argomenti come questo:

Argomenti[i]

dove i è il numero di indice dell'argomento, a partire da 0. Si accede al primo argomento passato alla funzione come argomenti . E per ottenere il numero di tutti gli argomenti - arguments.length .

Con l'oggetto arguments, puoi chiamare una funzione passando ad essa più argomenti di quelli che hai formalmente dichiarato di accettare. Questo è molto utile se non sai esattamente quanti argomenti dovrebbe prendere la tua funzione. È possibile utilizzare arguments.length per determinare il numero di argomenti passati a una funzione e quindi accedere a ciascun argomento utilizzando l'oggetto arguments.

Si consideri, ad esempio, una funzione che concatena più stringhe. L'unico argomento formale della funzione sarà una stringa che specifica i caratteri che separano gli elementi da concatenare. La funzione è così definita:

Funzione myConcat(separator) ( var result = ""; var i; // scorrere gli argomenti per (i = 1; i< arguments.length; i++) { result += arguments[i] + separator; } return result; }

Puoi passare un numero qualsiasi di argomenti a questa funzione e concatenerà ogni argomento in una singola stringa.

// restituisce "rosso, arancione, blu, " myConcat(", ", "rosso", "arancione", "blu"); // restituisce "elefante; giraffa; leone; ghepardo; " myConcat("; ", "elefante", "giraffa", "leone", "ghepardo"); // restituisce "salvia. basilico. origano. pepe. prezzemolo. " myConcat(". ", "salvia", "basilico", "origano", "pepe", "prezzemolo");

Perché arguments è uno pseudo-array, ad esso si applicano alcuni metodi di array, come per .. in

Funzione func() ( for (valore negli argomenti)( console.log(valore); ) ) func(1, 2, 3); // 1 // 2 // 3

Nota: argomenti è uno pseudo-array, ma non un array. Questo è uno pseudo-array che ha indici numerati e una proprietà di lunghezza. Tuttavia, non dispone di tutti i metodi di matrice.

Parametri di riposo

Due fattori hanno influenzato l'introduzione delle funzioni delle frecce: le funzioni più brevi e il lessico di questo.

Funzioni più brevi

Alcuni modelli di funzione incoraggiano l'uso di funzioni più brevi. Confrontare:

Var a = [ "Idrogeno", "Elio", "Litio", "Berillio" ]; var a2 = a.map(function(s) ( return s.length; )); log della console(a2); // logs var a3 = a.map(s => s.length); log della console(a3); // registri

Vocabolario questo

Prima delle funzioni freccia, ogni nuova funzione definiva il proprio questo valore (nuovo oggetto nel caso di un costruttore, non definito in modalità rigorosa, oggetto contesto se la funzione viene chiamata come metodo su un oggetto, ecc.). Questo si è rivelato fastidioso in termini di stile di programmazione orientato agli oggetti.

Function Person() ( // Il costruttore Person() definisce `this` come se stesso. this.age = 0; setInterval(function growUp() ( // Senza modalità rigorosa, growUp() definisce `this` // come globale object , che è diverso da `this` // definito dal costruttore Person().this.age++; ), 1000); ) var p = new Person();

In ECMAScript 3/5, questo problema è stato risolto assegnando il valore a una variabile che poteva essere chiusa.

Function Person() ( var self = this; // Alcuni scelgono `that` invece di `self`. // Scegline uno e sii coerente. self.age = 0; setInterval(function growUp() ( // Il callback si riferisce a la variabile `self` di cui // il valore è l'oggetto atteso.self.age++; ), 1000); )

Vedere anche Function in JavaScript Reference per ulteriori informazioni sulle funzioni come oggetto.

Qualsiasi programmatore sa bene quali sono le funzioni e perché sono necessarie. Tuttavia, le funzioni nel linguaggio Javascript hanno alcune particolarità. Se stai programmando in questo linguaggio da molto tempo, probabilmente saprai che ce ne sono diversi. Se provieni da un'altra lingua, durante la lettura di alcuni articoli, molto probabilmente hai visto questa, strana a prima vista, dichiarazione di funzione:

Var add = function(arg1, arg2) ( var sum = arg1 + arg2; return sum; ) var result = add(5, 2); //il risultato è ora 7

Cioè, la funzione, in primo luogo, non ha un nome. In secondo luogo, viene assegnato a una variabile, ma non solo assegnato, ma il suo corpo va immediatamente. Personalmente, per me, che in precedenza avevo scritto in linguaggi come VB, C ++, un annuncio del genere ha causato sconcerto e incomprensione su come funziona e perché scrivere in quel modo.

Sono abituato alla dichiarazione di funzione "classica" e alla chiamata, in questo modo:

Funzione add(arg1, arg2) ( var sum = arg1 + arg2; return sum; ) var result = add(5, 3); //il risultato è ora 8

Ed è qui che veniamo alle caratteristiche delle funzioni in Javascript. Per facilità di comprensione, immagina che una funzione in JS sia un valore ordinario, come un numero o una stringa. Puoi scrivere il numero 5 nella variabile di risultato, giusto? O qualcosa di più complesso, come un array, e poi visualizzarlo sullo schermo? Puoi. Quindi, se immaginiamo che una funzione sia un valore ordinario, anche se una struttura molto complessa, allora il primo modo di dichiarare non sembra più essere qualcosa di incredibile.

Il prossimo fatto interessante è una logica continuazione del primo. Dopo aver inserito i dati in una variabile, possiamo passare i dati a un'altra variabile usando il nome di questa variabile:

Var a = 5; var b = a; avviso(b); //uscite 5

La solita cosa. Ora dai un'occhiata a questo codice:

Var add = function(arg1, arg2) ( var sum = arg1 + arg2; somma restituita; ) var calcSum = aggiungi; avviso(calcSum(5, 6)); //uscite 11

Stai iniziando a indovinare? Poiché una funzione è come una variabile, possiamo "propagarla" mediante assegnazione ordinaria ad altre variabili, trasformandole anche in funzioni. Ora calcSum può anche aggiungere due numeri. Tuttavia, il codice

Somma Varcalc = aggiungi(1, 1); //calcSum ora è uguale a 2, questa non è una funzione, ma una variabile con un numero alert(calcSum(5, 6)); //sbaglio

Non verrà eseguito, perché nella prima riga non abbiamo assegnato la funzione stessa, ma il risultato della sua esecuzione (le parentesi indicano che la funzione deve essere eseguita, non assegnata).

Se è necessario chiamare una funzione su se stessa, questo viene fatto come segue:

Var calcFact = funzione fact(val) ( if (val == 1) ? val: val * fact(val - 1); // calcola fattoriale usando la ricorsione ) alert(calcFact(4)); //uscite 24

Qui, assegnando la funzione a una variabile, le abbiamo dato il nome fact. Tuttavia, questo nome sarà disponibile solo all'interno della funzione stessa e in nessun altro luogo. Le ragioni di ciò risiedono nel principio dell'interprete e esulano dallo scopo della lezione.

Ti starai chiedendo: "Hmm, caratteristica interessante! Ma qual è il vantaggio di farlo? Ci sono situazioni in cui è inevitabile, o almeno più conveniente di una normale dichiarazione?". Non mi impegno ad affermare che ci sono situazioni in cui è impossibile fare a meno di un tale approccio, ma posso fare un esempio in cui riduce la quantità di codice. Diciamo che devi salutare una persona a seconda dell'ora del giorno:

Var date = new Date(); var ciao = (date.getHours()< 12) ? function() {alert("Доброе утро!")} : (date.getHours() < 18) ? function() {alert("Добрый день!")} : function() {alert("Добрый вечер!")}; hello();

Come puoi vedere, le funzioni sono estremamente semplici, con un solo comando di avviso.

Se decidessimo di seguire la via "classica", allora dovremmo scrivere tre funzioni separate e quindi chiamarle nella condizione di test del tempo:

Function goodMorning() ( alert("Buongiorno!"); ) function goodAfternoon() ( alert("Buon pomeriggio!"); ) function goodEvning() ( alert("Buonasera!"); ) var date = new Date (); (data.getHours()< 12) ? goodMorning() : (date.getHours() < 18) ? goodAfternoon() : goodEvning();

Il codice è cresciuto in modo significativo visivamente, anche se abbiamo usato la forma abbreviata dell'istruzione condizionale. Se assumiamo che il file contenga funzioni davvero importanti che eseguono calcoli, inquinare l'elenco con tali mini-funzioni che non hanno una logica importante e che molto probabilmente vengono utilizzate solo una volta, non è una buona idea. Inoltre, siamo costretti a dare a ciascuna funzione un nome univoco e a specificarlo durante la chiamata. Pertanto, se devi cambiare il nome di uno di essi, dovrai cambiarlo in due punti, il che aumenta la probabilità di un errore.

In secondo luogo, se utilizziamo il metodo "classico", perdiamo la capacità di assegnare una funzione a una variabile. Cioè, scrivi

Funzione add(a, b) ( return a + b; ) var calcSum = add; calcSum(5, 5);

Già impossibile. Pertanto, nel nostro esempio, se abbiamo ancora bisogno di salutare l'ospite più di una volta, dovremo duplicare ogni volta questo frammento:

(data.getHours()< 12) ? goodMorning() : (date.getHours() < 18) ? goodAfternoon() : goodEvning();

E nel primo caso basterà scrivere solo hello(); e il risultato sarà lo stesso.

Ti ho parlato di una caratteristica interessante delle funzioni JS e ho fornito esempi. Così l'hai visto modi per chiamare funzioni in Javascript non sono limitati a una singola specie. Anche se non riesci a trovare immediatamente l'uso di queste funzionalità nei tuoi progetti, almeno saprai che tali funzionalità esistono. E quando si presenta un'opportunità davvero buona, puoi ridurre la quantità di codice ed evitare inutili confusioni ed errori.!

Questo articolo descrive le funzionalità di Javascript a livello di lingua: creazione, opzioni, trucchi, chiusure e altro.

Creazione di funzioni

Ci sono 3 modi per creare una funzione. La principale differenza come risultato del loro lavoro è che la funzione denominata è visibile ovunque e quella anonima è visibile solo dopo la dichiarazione:

Funzioni - Oggetti

In javascript, le funzioni sono oggetti a tutti gli effetti della classe Function incorporata. Ecco perché possono essere assegnati a variabili, passati e, ovviamente, hanno proprietà:

Funzione f() ( ... ) f.test = 6 ... alert(f.test) // 6

Le proprietà della funzione sono disponibili anche all'interno della funzione, quindi possono essere utilizzate come variabili statiche.

Per esempio,

Funzione func() ( var funcObj = arguments.callee funcObj.test++ alert(funcObj.test) ) func.test = 1 func() func()

All'inizio del lavoro, ogni funzione crea al suo interno una variabile arguments e assegna arguments.callee un riferimento a se stessa. Quindi arguments.callee.test è una proprietà di func.test , ovvero una variabile statica test.

Nell'esempio, era impossibile effettuare un incarico:

Vartest = argomenti.callee.test test++

perché in questo caso l'operazione ++ funzionerebbe sulla variabile locale test e non sulla proprietà test dell'oggetto funzione.

L'oggetto arguments contiene anche tutti gli argomenti e può essere convertito in un array (sebbene non lo sia), ne parleremo più avanti nella sezione sui parametri.

Ambiti

Ogni funzione, più precisamente, anche ogni avvio di funzione, imposta il proprio ambito individuale.

Le variabili possono essere dichiarate ovunque. La parola chiave var specifica una variabile nell'ambito corrente. Se lo dimentichi, la variabile finirà nell'oggetto finestra globale. Sono possibili intersezioni impreviste con altre variabili della finestra, conflitti e glitch.

A differenza di alcuni linguaggi, i blocchi non definiscono un ambito separato. Non importa se la variabile è definita all'interno o all'esterno del blocco. Quindi questi due frammenti sono perfettamente equivalenti:

Una variabile definita tramite var è visibile ovunque nell'ambito, anche prima dell'istruzione var. Ad esempio, creiamo una funzione che cambierà la variabile, var per la quale è sotto.

Per esempio:

Funzione a() ( z = 5 // cambierà z localmente.. // .. perché z è dichiarato tramite var var z ) // cancella z test // cancella za() globale per ogni evenienza alert(window.z) // => non definito poiché z è stato modificato localmente

Parametri di funzione

Le funzioni possono essere eseguite con qualsiasi numero di parametri.

Se alla funzione vengono passati meno parametri di quelli presenti nella definizione, quelli mancanti vengono considerati non definiti.

La seguente funzione restituisce il tempo necessario per coprire la distanza a una velocità uniforme.

La prima volta che la funzione viene eseguita con gli argomenti distance=10 , speed=undefined . Solitamente questa situazione, se supportata dalla funzione, fornisce un valore di default:

// se la velocità è falsa(undefined, 0, false...) - sostituisci 10 velocità = velocità || 10

Operatore || in javascript non restituisce true/false , ma il valore stesso (il primo che esegue il cast su true).

Pertanto, viene utilizzato per impostare i valori predefiniti. Nella nostra chiamata, la velocità sarà valutata come non definita || 10 = 10.

Quindi il risultato sarà 10/10 = 1 .

Il secondo lancio è standard.

La terza esecuzione specifica alcuni argomenti aggiuntivi. La funzione non funziona con argomenti aggiuntivi, quindi vengono semplicemente ignorati.

Bene, in quest'ultimo caso, non ci sono argomenti, quindi distance = undefined , e abbiamo il risultato della divisione undefined/10 = NaN (Not-A-Number, si è verificato un errore).

Lavorare con un numero indefinito di parametri

Appena prima di entrare nel corpo della funzione, viene creato automaticamente un oggetto arguments che contiene

  1. Chiama argomenti, a partire da zero
  2. La lunghezza nella proprietà length
  3. Riferimento alla funzione stessa nella proprietà chiamata

Per esempio,

Funzione func() ( for(var i=0;i

La proprietà arguments è come una matrice in quanto ha una lunghezza e indici numerici. In effetti, gli argomenti non appartengono alla classe Array e non ne contengono i metodi, come push , pop e altri.

Se vuoi comunque utilizzare questi metodi, ad esempio, per chiamare un'altra funzione con gli stessi argomenti, ma oltre alla prima, puoi creare un vero array da argomenti:

Var args = Array.prototype.slice.call(arguments) // .. ora args è un vero array di argomenti.. args.shift() ...

Puoi chiamare una funzione su un array di argomenti usando apply:

Var func = function(a,b) ( alert(a+b) ) var arr = func.apply(null, arr) // => alert(3)

Esempio di passaggio di una funzione per riferimento

Una funzione può essere facilmente passata come argomento a un'altra funzione.

Ad esempio, map prende una funzione func, la applica a ogni elemento dell'array arr e restituisce l'array risultante:

Var map = function(func, arr) ( var result = for(var i=0; i

Esempio di utilizzo:

Mappa(esegui, ) // =

Oppure puoi creare una funzione anonima direttamente nella chiamata della mappa:

// la funzione anonima triplica i numeri map(function (a) ( return a*3 ) , ) // =

Comprimere i parametri in un oggetto

Ci sono funzioni i cui argomenti variano notevolmente.

Per esempio:

// solo una parte degli argomenti può essere specificata // non specificata - calcolata o utilizzata per impostazione predefinita funzione resize(toWidth, toHeight, saveProportions, animate) ( // valori predefiniti saveProportions = saveProportions || true animate = animate || true toHeight = toHeight | | ... )

Una chiamata con parametri opzionali deve essere eseguita in questo modo:

resize(100, null, null, true)

Per evitare valori null non necessari e rendere il codice più comprensibile, usano qualcosa come gli "argomenti delle parole chiave" che esistono in Python e Ruby. Per fare ciò, molti parametri vengono compressi in un unico oggetto:

Funzione resize(setup) ( // valori predefiniti var saveProportions = setup.saveProportions || true var animate = setup.animate || true var toHeight = setup.toHeight || ... )

La chiamata ora è molto più semplice:

Var setup = (toWidth: 100, animate: true) resize(setup) // o resize((toWidth: 100, animate: true))

Sì, molto più chiaro. E se ci sono più di 5 parametri, in generale - l'unico modo normale.

Inoltre, è più conveniente creare sequenze di chiamate con un oggetto come:

var setup = (toWidth: 100, animate: true, saveProportions: false) resize(setup) setup.toWidth = 200 resize(setup)

Funzioni

Funzioneè un blocco di codice JavaScript che viene definito una volta e può essere eseguito o chiamato più volte. Potresti già avere familiarità con il concetto di "funzione" con un altro nome, come una subroutine o una procedura. Le funzioni possono avere parametri: una definizione di funzione può includere un elenco di identificatori chiamati parametri che agiscono come variabili locali nel corpo della funzione.

Quando le funzioni vengono chiamate, possono essere passati valori o argomenti corrispondenti ai loro parametri. Le funzioni spesso usano i loro argomenti per calcolare un valore restituito, che è il valore di un'espressione di chiamata di funzione. Oltre agli argomenti, quando si chiama una funzione, viene passato un altro valore che determina il contesto della chiamata: il valore nella parola chiave questo.

Le funzioni in JavaScript sono oggetti e possono essere utilizzate in molti modi. Ad esempio, le funzioni possono essere assegnate a variabili e passate ad altre funzioni. Poiché le funzioni sono oggetti, è possibile assegnare valori alle loro proprietà e persino chiamarne i metodi.

JavaScript consente di annidare le definizioni delle funzioni all'interno di altre funzioni e tali funzioni avranno accesso a tutte le variabili presenti nell'ambito della definizione.

Definizione di funzione

Una definizione di funzione inizia con una parola chiave funzione seguito dai seguenti componenti:

Identificatore che definisce il nome della funzione

Il nome è una parte obbligatoria dell'istruzione di dichiarazione della funzione: verrà utilizzato per creare una nuova variabile a cui verrà assegnato il nuovo oggetto funzione. Nelle espressioni di definizione di funzione, il nome può essere omesso: se presente, il nome farà riferimento all'oggetto funzione solo nel corpo della funzione stessa.

Una coppia di parentesi attorno a un elenco separato da virgole di zero o più identificatori

Questi identificatori definiranno i nomi dei parametri della funzione e possono essere utilizzati come variabili locali nel corpo della funzione.

Un paio di parentesi graffe con zero o più istruzioni JavaScript all'interno

Queste istruzioni costituiscono il corpo della funzione: vengono eseguite ogni volta che la funzione viene chiamata.

L'esempio seguente mostra diverse definizioni di funzioni sotto forma di istruzioni ed espressioni. Si noti che le definizioni di funzione come espressioni sono utili solo se fanno parte di espressioni più grandi, come un'assegnazione o una chiamata di funzione, che eseguono alcune azioni utilizzando la funzione appena dichiarata:

// Stampa i nomi e i valori di tutte le proprietà della funzione oggetto obj printprops(obj) ( for(var p in obj) console.log(p + ": " + obj[p] + "\n"); ) // Calcola la distanza tra i punti (x1,y1) e (x2,y2) function distance(x1, y1, x2, y2) ( var dx = x2 - x1; var dy = y2 - y1; return Math.sqrt( dx*dx + dy*dy ); ) // Funzione ricorsiva (che si richiama) che calcola la funzione fattoriale fattoriale(x) ( if (x

Si noti che nelle espressioni di definizione di funzione, il nome della funzione può essere omesso. Un'istruzione di dichiarazione di funzione dichiara effettivamente una variabile e le assegna un oggetto funzione.

Un'espressione di definizione di funzione, al contrario, non dichiara una variabile. Tuttavia, le espressioni di definizione possono specificare un nome di funzione, come nella funzione fattoriale sopra, che potrebbe essere richiesta nel corpo della funzione per chiamare se stessa. Se un'espressione di definizione di funzione include un nome, quel nome farà riferimento all'oggetto funzione nell'ambito della funzione. In effetti, il nome della funzione diventa una variabile locale, accessibile solo all'interno del corpo della funzione. Nella maggior parte dei casi, il nome della funzione non è richiesto nelle espressioni di definizione, rendendo le definizioni più compatte.

Si noti che la maggior parte (ma non tutte) delle funzioni nell'esempio contengono un'istruzione return. L'istruzione return termina l'esecuzione della funzione e restituisce il valore della sua espressione (se specificato) al programma chiamante. Se non è presente alcuna espressione nell'istruzione return, restituisce undefined. Se non è presente alcuna istruzione return nella funzione, l'interprete eseguirà semplicemente tutte le istruzioni nel corpo della funzione e restituirà undefined al chiamante.

La maggior parte delle funzioni nell'esempio valuta un valore e utilizza un'istruzione return per restituire quel valore al chiamante. La funzione printprops() è leggermente diversa in questo senso: il suo compito è stampare i nomi delle proprietà di un oggetto. Non è necessario restituire alcun valore, quindi nella funzione non è presente alcuna istruzione di ritorno. La funzione printprops() restituirà sempre undefined. (Le funzioni che non hanno un valore restituito sono talvolta chiamate procedure.)

Funzioni di chiamata

Il codice del programma che costituisce il corpo di una funzione viene eseguito non nel momento in cui la funzione viene definita, ma nel momento in cui viene chiamata. Le chiamate di funzione vengono effettuate utilizzando un'espressione di chiamata. Un'espressione di chiamata consiste in un'espressione di chiamata di funzione che restituisce un oggetto funzione, seguito da parentesi con un elenco separato da virgole di zero o più espressioni di argomento all'interno.

Se un'espressione di accesso alla funzione è un'espressione di accesso alla proprietà, se la funzione è una proprietà di un oggetto o un elemento di una matrice (ad esempio, un metodo), l'espressione di chiamata è un'espressione di chiamata di metodo. Il frammento di codice seguente mostra diversi esempi di normali espressioni di chiamata di funzione:

Printprops((x:4, età: 24)); var d = distanza(1,1,5,6); var f = fattoriale(5) / fattoriale(12); f = quadrato(5);

Quando viene chiamata una funzione, vengono valutate tutte le espressioni di argomento (specificate tra parentesi) e i valori risultanti vengono utilizzati come argomenti di funzione. Questi valori sono assegnati ai parametri i cui nomi sono elencati nella definizione della funzione. Nel corpo della funzione, le espressioni di accesso ai parametri restituiscono i valori degli argomenti corrispondenti.

Quando viene chiamata una funzione normale, il valore restituito dalla funzione diventa il valore dell'espressione di chiamata. Se la funzione ritorna quando l'interprete raggiunge la fine della funzione, viene restituito undefined. Se una funzione ritorna come risultato di un'istruzione return, viene restituito il valore dell'espressione che segue l'istruzione return, o non definito se l'istruzione return non ha espressione.

Metodo non è altro che una funzione memorizzata come proprietà di un oggetto. Data una funzione func e un oggetto obj, puoi definire un metodo sull'oggetto obj chiamato metodo, come mostrato di seguito:

// Definisci un oggetto semplice e una funzione var obj = (); function func(a, b) ( return a+b;) // Aggiunge un metodo all'oggetto obj obj.method = func; // Ora possiamo chiamare questo metodo var result = obj.method(4, 5);

Il modo più comune per chiamare i metodi consiste nell'usare la forma dell'operatore punto per l'accesso alla proprietà, ma puoi anche usare la forma della parentesi quadra per l'accesso alla proprietà. Ad esempio, entrambe le seguenti espressioni sono espressioni di chiamata di metodo:

Risultato = obj.method(4, 5); risultato = obj["metodo"](4, 5);

Gli argomenti e il valore restituito di una chiamata al metodo vengono gestiti esattamente allo stesso modo di una normale chiamata di funzione. Tuttavia, l'invocazione del metodo presenta una differenza importante: il contesto dell'invocazione. Un'espressione di accesso alla proprietà è composta da due parti: un oggetto (obj in questo caso) e un nome di proprietà (metodo). In tali espressioni di chiamata al metodo, l'oggetto obj diventa il contesto della chiamata e il corpo della funzione può fare riferimento a questo oggetto utilizzando la parola chiave this. Per esempio:

Var obj = ( x: 0, y: 0, // Aggiungi metodo: function(a, b) ( this.x = a; this.y = b; ), // Un altro metodo sum: function() ( return this .x + this.y ) ); // Metodi di chiamata obj.add(15, 4); console.log(obj.sum()); // 19

I metodi e la parola chiave this sono centrali nel paradigma della programmazione orientata agli oggetti. Qualsiasi funzione utilizzata come metodo riceve effettivamente un argomento implicito, l'oggetto su cui è stata chiamata. In genere, i metodi eseguono alcune azioni su un oggetto e la sintassi della chiamata al metodo riflette chiaramente il fatto che una funzione opera su un oggetto.

Si noti che questa è una parola chiave, non un nome di variabile o proprietà. La sintassi JavaScript non consente di assegnare valori all'elemento this.

Argomenti e parametri di funzione

In JavaScript, le definizioni di funzione non specificano i tipi di parametro e quando le funzioni vengono chiamate, non vengono eseguiti controlli di tipo sui valori degli argomenti passati. Infatti, quando si chiamano funzioni in JavaScript, anche il numero di argomenti non viene verificato. Le sottosezioni seguenti descrivono cosa succede se il numero di argomenti in una chiamata di funzione è minore o maggiore del numero di parametri dichiarati. Dimostrano anche come controllare in modo esplicito i tipi di argomenti della funzione se si desidera assicurarsi che la funzione non venga chiamata con argomenti errati.

Argomenti opzionali

Quando il numero di argomenti in una chiamata di funzione è inferiore al numero di parametri dichiarati, gli argomenti mancanti vengono impostati su undefined. Spesso è conveniente scrivere funzioni in modo che alcuni argomenti siano facoltativi e possano essere omessi quando la funzione viene chiamata. In questo caso, è auspicabile prevedere la possibilità di assegnare valori di default ragionevolmente ragionevoli a parametri che possono essere omessi. Per esempio:

// Aggiungi i nomi enumerati // delle proprietà dell'oggetto obj all'array arr e lo restituisce. Se non è stato passato alcun argomento // arr, crea e restituisce una nuova funzione array getPropertyNames(obj, /* optional */ arr) ( if (arr === undefined) arr = ; // Se l'array non è definito, crea un nuovo one for( var property in obj) arr.push(property); return arr; ) // Questa funzione può essere chiamata con 1 o 2 argomenti: var a = getPropertyNames((x:1, y:1)); // Ottieni le proprietà dell'oggetto nel nuovo array getPropertyNames((z:5),a); // aggiunge le proprietà del nuovo oggetto a questo array console.log(a); // ["x", "y", "z"]

Si noti che quando si dichiarano le funzioni, gli argomenti facoltativi devono terminare l'elenco di argomenti in modo che possano essere omessi. Un programmatore che scrive una chiamata alla tua funzione non può passare il secondo argomento e omettere il primo: sarà costretto a passare esplicitamente undefined nel primo argomento. Notare anche il commento /* optional */ nella definizione della funzione, che sottolinea il fatto che il parametro è opzionale.

Elenchi di argomenti a lunghezza variabile

Se il numero di argomenti in una chiamata di funzione supera il numero di nomi di parametri, la funzione non è più in grado di accedere direttamente ai valori senza nome. Viene fornita la soluzione a questo problema Argomenti oggetto. Nel corpo della funzione, l'identificatore argomenti fa riferimento all'oggetto Argomenti presente nella chiamata. L'oggetto Arguments è un oggetto simile a una matrice che consente di recuperare i valori passati a una funzione in base ai loro numeri anziché ai loro nomi.

Supponiamo che sia stata definita una funzione func che richiede un singolo argomento x. Se chiami questa funzione con due argomenti, il primo sarà disponibile all'interno della funzione con il nome del parametro x o come argomenti. Il secondo argomento sarà disponibile solo come argomenti. Inoltre, come i veri array, gli argomenti hanno una proprietà length che specifica il numero di elementi che contiene. Cioè, nel corpo di una funzione func chiamata con due argomenti, arguments.length è 2.

L'oggetto Argomenti può essere utilizzato per diversi scopi. L'esempio seguente mostra come usarlo per verificare se una funzione è stata chiamata con il numero corretto di argomenti, perché JavaScript non lo farà per te:

Funzione func(x, y, z) ( // Per prima cosa controlla se è stato passato il numero corretto di argomenti if (arguments.length != 3) ( throw new Error("Func function call with " + arguments.length + " argomenti, ma richiesto 3."); ) // E ora il codice della funzione stesso... )

Si noti che spesso non è necessario controllare il numero di argomenti, come in questo esempio. Il comportamento predefinito dell'interprete JavaScript va bene per la maggior parte dei casi: gli argomenti mancanti vengono sostituiti con non definiti e gli argomenti aggiuntivi vengono semplicemente ignorati.

L'oggetto Arguments illustra un'importante caratteristica delle funzioni JavaScript: possono essere scritte per accettare un numero qualsiasi di argomenti. La seguente funzione accetta un numero qualsiasi di argomenti e restituisce il valore del più grande di essi (la funzione incorporata Math.max() si comporta in modo simile):

Funzione maxNumber() ( var m = Number.NEGATIVE_INFINITY; // Scorri tutti gli argomenti, trova e // memorizza il più grande di essi for(var i = 0; im) m = arguments[i]; // Restituisce il valore più grande return m ; ) var più grande = maxNumber(1, 10, 100, 2, 3, 1000, 4, 5, 10000, 6); // 10000

Funzioni come questa che possono accettare un numero arbitrario di argomenti sono chiamate funzioni variadiche, funzioni di arità variabile o funzioni varags. Questo termine è nato con l'avvento del linguaggio di programmazione C.

Si noti che le funzioni con un numero variabile di argomenti non devono essere chiamate con un elenco di argomenti vuoto. È opportuno utilizzare l'oggetto arguments quando si scrive una funzione che prevede di ricevere un numero fisso di argomenti con nome richiesti, seguito da un numero arbitrario di argomenti senza nome facoltativi.

Non va dimenticato che arguments non è in realtà un array: è un oggetto Arguments. Ogni oggetto Arguments ha elementi di matrice numerati e una proprietà di lunghezza, ma tecnicamente non è una matrice. È meglio pensarlo come un oggetto che ha alcune proprietà enumerate.

Oltre agli elementi della sua matrice, l'oggetto Arguments definisce le proprietà chiamato e chiamante. Il tentativo di modificare i valori di queste proprietà in modalità rigorosa di ECMAScript 5 è garantito per generare un'eccezione TypeError. Tuttavia, in modalità lassista, lo standard ECMAScript afferma che la proprietà chiamata fa riferimento alla funzione attualmente in esecuzione. La proprietà caller non è standard, ma è presente in molte implementazioni e fa riferimento alla funzione che ha chiamato quella corrente.

La proprietà chiamante può essere utilizzata per accedere allo stack di chiamate e la proprietà chiamata è particolarmente utile per chiamare ricorsivamente funzioni senza nome:

Fattoriale variabile = funzione(x) ( se (x

Proprietà e metodi delle funzioni

Abbiamo visto che le funzioni possono essere utilizzate come valori nei programmi JavaScript. L'operatore typeof restituisce la stringa "funzione" per le funzioni, ma le funzioni JavaScript sono in realtà un tipo speciale di oggetto. E poiché le funzioni sono oggetti, hanno proprietà e metodi come qualsiasi altro oggetto. Esiste anche un costruttore Function() che crea nuovi oggetti funzione. Le seguenti sottosezioni descrivono le proprietà ei metodi delle funzioni.

proprietà di lunghezza

Nel corpo della funzione, la proprietà arguments.length determina il numero di argomenti passati alla funzione. Tuttavia, la proprietà length della funzione stessa ha un significato diverso. Questa proprietà di sola lettura restituisce il numero di argomenti che la funzione si aspetta di ricevere, ovvero il numero di parametri dichiarati.

Il frammento di codice seguente definisce una funzione denominata check() che riceve un array di argomenti da un'altra funzione. Confronta la proprietà arguments.length (il numero di argomenti effettivamente passati) con la proprietà arguments.callee.length (il numero di argomenti previsti) per determinare se alla funzione sono stati passati tutti gli argomenti previsti. Se i valori non corrispondono, viene generata un'eccezione. La funzione check() è seguita dalla funzione test func(), che mostra come utilizzare la funzione check():

// Questa funzione usa arguments.callee, quindi // non funzionerà in modalità rigorosa function check(args) ( var actual = args.length; // Numero effettivo di argomenti var Expect = args.callee.length; // Argomenti del numero previsto if (actual !== previsto) // Se non corrispondono, viene generata un'eccezione throw new Error("expected: " + Expected + "; ricevuto " + actual); ) function func(x, y , z) ( // Controlla il numero di argomenti previsti e effettivamente passati check(arguments); // Ora esegui il resto della funzione return x + y + z; )

proprietà prototipo

Ogni funzione ha una proprietà prototipo che fa riferimento a un oggetto noto come oggetto prototipo. Ogni funzione ha il proprio oggetto prototipo. Quando una funzione viene utilizzata come costruttore, l'oggetto appena creato eredita le proprietà di quell'oggetto prototipo.

I prototipi e la proprietà del prototipo sono stati discussi in un articolo precedente.

call() e apply()

I metodi call() e apply() consentono di chiamare una funzione indirettamente come se fosse un metodo di un altro oggetto. Il primo argomento sia per call() che per apply() è l'oggetto su cui viene chiamata la funzione; questo argomento definisce il contesto della chiamata e diventa il valore della parola chiave this nel corpo della funzione. Per chiamare la funzione func() (senza argomenti) come metodo dell'oggetto obj, puoi usare uno dei metodi, call() o apply():

Func.call(obj); func apply(obj);

In entrambi i modi di chiamarlo equivale al seguente snippet (supponendo che obj non abbia una proprietà denominata m):

obj.m = funzione; // Rendi temporaneamente func un metodo obj obj.m(); // Chiamalo senza argomenti. elimina oggetto; // Rimuovi il metodo temporaneo.

Nella modalità rigorosa di ECMAScript 5, il primo argomento dei metodi call() e apply() diventa il valore this, anche se è un valore semplice, nullo o non definito. In ECMAScript 3 e in modalità non rigorosa, null e undefined vengono sostituiti dall'oggetto globale e un valore semplice dall'oggetto wrapper appropriato.

Tutti gli altri argomenti del metodo call() che seguono il primo argomento, che specifica il contesto della chiamata, vengono passati alla funzione chiamata. Il metodo apply() agisce come il metodo call(), tranne per il fatto che gli argomenti della funzione vengono passati come un array. Se una funzione è in grado di gestire un numero arbitrario di argomenti, il metodo apply() può essere utilizzato per chiamare tale funzione nel contesto di un array di lunghezza arbitraria.

L'esempio seguente mostra l'uso pratico del metodo call():

// Di seguito sono riportate due funzioni che mostrano le proprietà e // i valori delle proprietà di un oggetto arbitrario. Il metodo di visualizzazione // viene passato come argomento func function print1(func, obj) ( for (n in obj) func(n +": " + obj[n]); ) function print2(func, objDevice, obj) ( for ( n in obj) func.call(objDevice, n +": " + obj[n]); ) var obj = (x:5, y:10); print2(document.write, document, obj); // Funziona correttamente print2(console.log, console, obj); print1(document.write, obj); // Verrà sollevata un'eccezione di chiamata illegale perché print1(console.log, obj); // non è possibile chiamare questi metodi senza un oggetto contesto

metodo bind()

Il metodo bind() è apparso per la prima volta in ECMAScript 5, ma è facile da imitare in ECMAScript 3. Come suggerisce il nome, lo scopo principale del metodo bind() è associare una funzione a un oggetto. Se chiami il metodo bind() di func e gli passi un oggetto obj, restituirà una nuova funzione. La chiamata della nuova funzione (come una normale funzione) chiamerà la funzione originale func come metodo dell'oggetto obj. Tutti gli argomenti passati alla nuova funzione verranno passati alla funzione originale. Per esempio:

// Funzione per associare la funzione func(y) ( return this.x + y; ) var obj = (x:1); // Oggetto da associare a var g = func.bind(obj); // Chiamando g(x) chiamerà obj.func(x)

Questo tipo di associazione è facile da implementare in ECMAScript 3, come mostrato di seguito:

// Restituisce una funzione che chiama func come metodo su obj // e gli passa tutti i suoi argomenti function bind(func, obj) ( if (func.bind) return func.bind(obj); // Usa il metodo bind se disponibile else return function() ( // Else bind come sotto return func. apply(obj, arguments); ); )

Il metodo bind() in ECMAScript 5 fa molto di più che semplicemente associare una funzione a un oggetto. Esegue anche un'applicazione parziale: oltre al valore this, tutti gli argomenti passati al metodo bind() dopo il suo primo argomento verranno vincolati. L'applicazione parziale è una tecnica comune nella programmazione funzionale e talvolta viene chiamata al curry.

Articoli correlati in alto