În JavaScript, o funcție nu este o „structură magică a limbajului”, ci un tip special de valoare.
Sintaxa pe care am folosit-o înainte se numește declarație de funcție:
function sayHi() { alert( "Hello" );}
Există o altă sintaxă pentru crearea unei funcții care se numește expresie de funcție.
Acesta arată astfel:
let sayHi = function() { alert( "Hello" );};
Aici, funcția este creată și atribuită variabilei în mod explicit, ca orice altă valoare. Indiferent cum este definită funcția, aceasta este doar o valoare stocată în variabila sayHi
.
Semnificația acestor exemple de cod este aceeași: „creați o funcție și puneți-o în variabila sayHi
„.
Putem chiar să tipărim acea valoare folosind alert
:
function sayHi() { alert( "Hello" );}alert( sayHi ); // shows the function code
Rețineți că ultima linie nu execută funcția, deoarece nu există paranteze după sayHi
. Există limbaje de programare în care orice mențiune a numelui unei funcții determină execuția acesteia, dar JavaScript nu este așa.
În JavaScript, o funcție este o valoare, deci o putem trata ca pe o valoare. Codul de mai sus arată reprezentarea sa sub formă de șir de caractere, care este codul sursă.
Sigur, o funcție este o valoare specială, în sensul că o putem numi ca sayHi()
.
Dar este tot o valoare. Deci putem lucra cu ea ca și cu alte tipuri de valori.
Potem copia o funcție într-o altă variabilă:
function sayHi() { // (1) create alert( "Hello" );}let func = sayHi; // (2) copyfunc(); // Hello // (3) run the copy (it works)!sayHi(); // Hello // this still works too (why wouldn't it)
Iată ce se întâmplă mai sus în detaliu:
- Declarația funcției
(1)
creează funcția și o pune în variabila numităsayHi
. - Linia
(2)
o copiază în variabilafunc
. Rețineți din nou: nu există paranteze dupăsayHi
. Dacă ar exista, atuncifunc = sayHi()
ar scrie rezultatul apeluluisayHi()
înfunc
, nu funcțiasayHi
în sine. - Acum funcția poate fi apelată atât ca
sayHi()
, cât și cafunc()
.
Rețineți că am fi putut, de asemenea, să folosim o expresie de funcție pentru a declara sayHi
, în prima linie:
let sayHi = function() { alert( "Hello" );};let func = sayHi;// ...
Toate lucrurile ar fi funcționat la fel.
S-ar putea să vă întrebați, de ce Function Expression are un punct și virgulă ;
la sfârșit, dar Function Declaration nu are:
function sayHi() { // ...}let sayHi = function() { // ...};
Răspunsul este simplu:
- Nu este nevoie de
;
la sfârșitul blocurilor de cod și al structurilor sintactice care le folosesc, cum ar fiif { ... }
,for { }
,function f { }
etc. - În interiorul instrucțiunii se utilizează o expresie de funcție:
let sayHi = ...;
, ca o valoare. Nu este un bloc de cod, ci mai degrabă o atribuire. Se recomandă folosirea punctului și virgula;
la sfârșitul instrucțiunilor, indiferent care este valoarea. Așadar, punctul și virgula de aici nu are legătură cu expresia de funcție în sine, ci doar încheie instrucțiunea.
Funcții de retur
Să ne uităm la mai multe exemple de trecere a funcțiilor ca valori și de utilizare a expresiilor de funcție.
Vom scrie o funcție ask(question, yes, no)
cu trei parametri:
question
Textul întrebării yes
Funcția care trebuie executată dacă răspunsul este „Da” no
Funcția care trebuie executată dacă răspunsul este „Nu”
Funcția trebuie să întrebe question
și, în funcție de răspunsul utilizatorului, să apeleze yes()
sau no()
:
function ask(question, yes, no) { if (confirm(question)) yes() else no();}function showOk() { alert( "You agreed." );}function showCancel() { alert( "You canceled the execution." );}// usage: functions showOk, showCancel are passed as arguments to askask("Do you agree?", showOk, showCancel);
În practică, astfel de funcții sunt destul de utile. Diferența majoră dintre un ask
din viața reală și exemplul de mai sus este că funcțiile din viața reală folosesc modalități mai complexe de interacțiune cu utilizatorul decât un simplu confirm
. În browser, o astfel de funcție desenează, de obicei, o fereastră de întrebări cu aspect plăcut. Dar asta este o altă poveste.
Argumentele showOk
și showCancel
din ask
se numesc funcții callback sau pur și simplu callback.
Ideea este că trecem o funcție și ne așteptăm ca aceasta să fie „chemată înapoi” mai târziu, dacă este necesar. În cazul nostru, showOk
devine callback pentru răspunsul „da”, iar showCancel
pentru răspunsul „nu”.
Potem folosi expresii de funcții pentru a scrie aceeași funcție mult mai scurt:
function ask(question, yes, no) { if (confirm(question)) yes() else no();}ask( "Do you agree?", function() { alert("You agreed."); }, function() { alert("You canceled the execution."); });
Aici, funcțiile sunt declarate chiar în interiorul apelului ask(...)
. Ele nu au nici un nume și, prin urmare, sunt numite anonime. Astfel de funcții nu sunt accesibile în afara lui ask
(pentru că nu sunt atribuite variabilelor), dar este exact ceea ce ne dorim aici.
Un astfel de cod apare în scripturile noastre foarte natural, este în spiritul lui JavaScript.
Valorile obișnuite, cum ar fi șirurile de caractere sau numerele, reprezintă datele.
O funcție poate fi percepută ca o acțiune.
O putem trece între variabile și o putem executa când dorim.
Expresie de funcție vs Declarație de funcție
Să formulăm principalele diferențe dintre declarațiile și expresiile de funcție.
În primul rând, sintaxa: cum să le diferențiem în cod.
-
Declarație de funcție: o funcție, declarată ca o instrucțiune separată, în fluxul principal de cod.
// Function Declarationfunction sum(a, b) { return a + b;}
Expresie de funcție: o funcție, creată în interiorul unei expresii sau în interiorul unei alte construcții sintactice. Aici, funcția este creată în partea dreaptă a „expresiei de atribuire”
=
:// Function Expressionlet sum = function(a, b) { return a + b;};
Diferența mai subtilă este atunci când o funcție este creată de motorul JavaScript.
O expresie de funcție este creată atunci când execuția ajunge la ea și este utilizabilă numai din acel moment.
După ce fluxul de execuție trece în partea dreaptă a asignării
let sum = function…
– iată, funcția este creată și poate fi utilizată (asignată, apelată, etc. ) de acum încolo.Declarațiile de funcții sunt diferite.
O Declarație de funcție poate fi apelată mai devreme decât este definită.
De exemplu, o Declarație de funcție globală este vizibilă în tot scriptul, indiferent unde se află.
Acest lucru se datorează algoritmilor interni. Când JavaScript se pregătește să ruleze scriptul, el caută mai întâi Declarații de funcții globale în acesta și creează funcțiile. Ne putem gândi la aceasta ca la o „etapă de inițializare”.
Și după ce toate Declarațiile de funcții sunt procesate, codul este executat. Deci are acces la aceste funcții.
De exemplu, așa funcționează:
sayHi("John"); // Hello, Johnfunction sayHi(name) { alert( `Hello, ${name}` );}
Declarația de funcție
sayHi
este creată atunci când JavaScript se pregătește să pornească scriptul și este vizibilă peste tot în el.…Dacă ar fi o expresie de funcție, atunci nu ar funcționa:
sayHi("John"); // error!let sayHi = function(name) { // (*) no magic any more alert( `Hello, ${name}` );};
Expresiile de funcție sunt create atunci când execuția ajunge la ele. Acest lucru s-ar întâmpla doar în linia
(*)
. Prea târziu.O altă caracteristică specială a Declarațiilor de funcții este sfera lor de cuprindere în bloc.
În modul strict, atunci când o Declarație de funcție se află în interiorul unui bloc de cod, ea este vizibilă peste tot în interiorul acelui bloc. Dar nu și în afara acestuia.
De exemplu, să ne imaginăm că trebuie să declarăm o funcție
welcome()
în funcție de variabilaage
pe care o primim în timpul execuției. Și apoi plănuim să o folosim ceva mai târziu.Dacă folosim declarația de funcție, aceasta nu va funcționa așa cum este prevăzut:
let age = prompt("What is your age?", 18);// conditionally declare a functionif (age < 18) { function welcome() { alert("Hello!"); }} else { function welcome() { alert("Greetings!"); }}// ...use it laterwelcome(); // Error: welcome is not defined
Aceasta pentru că o declarație de funcție este vizibilă doar în interiorul blocului de cod în care se află.
Iată un alt exemplu:
let age = 16; // take 16 as an exampleif (age < 18) { welcome(); // \ (runs) // | function welcome() { // | alert("Hello!"); // | Function Declaration is available } // | everywhere in the block where it's declared // | welcome(); // / (runs)} else { function welcome() { alert("Greetings!"); }}// Here we're out of curly braces,// so we can not see Function Declarations made inside of them.welcome(); // Error: welcome is not defined
Ce putem face pentru ca
welcome
să fie vizibilă în afara luiif
?Abordarea corectă ar fi să folosim o expresie de funcție și să atribuim
welcome
variabilei care este declarată în afara luiif
și care are vizibilitatea corespunzătoare.Acest cod funcționează conform intenției:
let age = prompt("What is your age?", 18);let welcome;if (age < 18) { welcome = function() { alert("Hello!"); };} else { welcome = function() { alert("Greetings!"); };}welcome(); // ok now
Sau am putea să îl simplificăm și mai mult folosind un operator semn de întrebare
?
:let age = prompt("What is your age?", 18);let welcome = (age < 18) ? function() { alert("Hello!"); } : function() { alert("Greetings!"); };welcome(); // ok now
Când să alegem declarația de funcție versus expresia de funcție?Ca regulă generală, atunci când trebuie să declarăm o funcție, prima care trebuie luată în considerare este sintaxa Function Declaration. Aceasta oferă mai multă libertate în ceea ce privește modul de organizare a codului nostru, deoarece putem apela astfel de funcții înainte de a fi declarate.
De asemenea, acest lucru este mai bun pentru lizibilitate, deoarece este mai ușor să căutăm
function f(…) {…}
în cod decâtlet f = function(…) {…};
. Declarațiile de funcții sunt mai „eye-catching”.…Dar dacă o declarație de funcții nu ne convine din anumite motive, sau avem nevoie de o declarație condiționată (tocmai am văzut un exemplu), atunci ar trebui folosită expresia de funcții.
Summary
- Funcțiile sunt valori. Ele pot fi atribuite, copiate sau declarate în orice loc din cod.
- Dacă funcția este declarată ca o instrucțiune separată în fluxul principal de cod, aceasta se numește „Declarație de funcție”.
- Dacă funcția este creată ca parte a unei expresii, aceasta se numește „Expresie de funcție”.
- Declarațiile de funcție sunt procesate înainte ca blocul de cod să fie executat. Ele sunt vizibile peste tot în bloc.
- Expresiile de funcție sunt create atunci când fluxul de execuție ajunge la ele.
În majoritatea cazurilor în care trebuie să declarăm o funcție, este preferabilă o Declarație de funcție, deoarece aceasta este vizibilă înainte de declarația propriu-zisă. Aceasta ne oferă mai multă flexibilitate în organizarea codului și, de obicei, este mai ușor de citit.
De aceea, ar trebui să folosim o Expresie de funcție numai atunci când o Declarație de funcție nu este potrivită pentru sarcina respectivă. Am văzut câteva exemple în acest capitol și vom mai vedea și altele în viitor.
.