Skip to content

Files

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Latest commit

53eaa18 · Jun 2, 2025

History

History
380 lines (256 loc) · 20.9 KB

File metadata and controls

380 lines (256 loc) · 20.9 KB

Ֆունկցիոնալ արտահայտություններ

JavaScript-ում ֆունկցիան «լեզվի կախարդական կառուցվածք» չէ, բայց արժեքի հատուկ տեսակ է:

Այն շարահյուսությունը, որ մինչ այս օգտագործել ենք, կոչվում է Function Declaration (Ֆունկցիոնալ Հռչակագիր):

function sayHi() {
  alert( "Ողջույն" );
}

Կա նաև այլ շարահյուսություն ֆունկցիա ստեղծելու համար, որը կոչվում է Function Expression (Ֆունկցիոնալ Արտահայտություն):

Դա մեզ թույլ է տալիս ստեղծել նոր ֆունկցիա ցանկացած արտահայտության մեջտեղում:

Օրինակ.

let sayHi = function() {
  alert( "Ողջույն" );
};

Այստեղ մենք կարող ենք տեսնել, որ sayHi փոփոխականը ստանում է արժեք՝ նոր ֆունկցիա, որը ստեղծվել է այսպես՝ function() { alert("Ողջույն"); }:

Քանի որ ֆունկցիայի ստեղծումը տեղի է ունենում վերագրման արտահայտության համատեքստում (= նշանի աջ կողմում), ապա սա Function Expression (Ֆունկցիոնալ Արտահայտություն) է:

Նկատի ունեցեք, որ function հիմնաբառից հետո չկա անվանում: Անվան բացթողումը թույլատրելի է Ֆունկցիոնալ Արտահայտությունների համար:

Այստեղ մենք անմիջապես վերագրում ենք այն փոփոխականի, ուստի այս կոդի նմուշների իմաստը նույնն է. «ստեղծել ֆունկցիա և տեղադրել այն sayHi փոփոխականում»:

Ավելի առաջադեմ իրավիճակներում, որոնց մենք ավելի ուշ կառնչվենք, ֆունկցիան կարող է ստեղծվել և անմիջապես կանչվել կամ պլանավորվել հետագա գործարկման համար, ոչ մի տեղ չպահվել, այդպիսով մնալ անանուն:

Ֆունկցիան արժեք է

Եկեք կրկնենք. անկախ նրանից, թե ինչպես է ստեղծվում ֆունկցիան, այն արժեք է: Վերոնշյալ երկու օրինակներն էլ sayHi փոփոխականում պահում են ֆունկցիա:

Մենք կարող ենք նույնիսկ տպել այդ արժեքը՝ օգտագործելով alert.

function sayHi() {
  alert( "Ողջույն" );
}

*!*
alert( sayHi ); // ցուցադրում է ֆունկցիայի կոդը
*/!*

Նկատի ունեցեք, որ վերջին տողը չի գործարկում ֆունկցիան, որովհետև sayHi-ից հետո չկան փակագծեր: Կան ծրագրավորման լեզուներ, որտեղ ֆունկցիայի անվան ցանկացած հիշատակում հանգեցնում է դրա գործարկմանը, բայց JavaScript-ը այդպիսին չէ։

JavaScript-ում ֆունկցիան արժեք է, այնպես որ մենք կարող ենք դրան վերաբերվել որպես արժեքի: Վերոնշյալ կոդը ցույց է տալիս իր տողային ներկայացումը, որը սկզբնական կոդ է:

Անշուշտ, ֆունկցիան հատուկ արժեք է, այն իմաստով, որ մենք կարող ենք այն կանչել որպես sayHi():

Բայց դա դեռևս արժեք է: Այսպիսով, մենք կարող ենք աշխատել դրա հետ այնպես, ինչպես այլ տեսակի արժեքների հետ:

Մենք կարող ենք պատճենել ֆունկցիան մեկ այլ փոփոխականում.

function sayHi() {     // (1) ստեղծել
  alert( "Ողջույն" );
}

let func = sayHi;      // (2) պատճենել

func(); // Ողջույն     // (3) գործարկել կրկնօրինակը (սա աշխատում է)
sayHi(); // Ողջույն    //     սա նույնպես դեռ աշխատում է (ինչու ոչ)

Ահա մանրամասն, թե ինչ է տեղի ունենում վերևում.

  1. Ֆունկցիոնալ Հռչակագիրը (1) ստեղծում է ֆունկցիա և տեղադրում այն sayHi անվանումով փոփոխականում:
  2. Տող (2)-ը պատճենում է այն func փոփոխականում: Կրկին նկատի ունեցեք. sayHi-ից հետո չկան փակագծեր: Եթե լինեին, ապա func = sayHi() կվերագրեր sayHi()կանչվելու արդյունքը func-ին, այլ ոչ հենց sayHi ֆունկցիան:
  3. Այժմ երկու եղանակով էլ ֆունկցիան կարող է կանչվել՝ sayHi() և func():

Մենք sayHi հռչակելու համար կարող էինք օգտագործել նաև Ֆունկցիոնալ Արտահայտություն առաջին տողում.

let sayHi = function() { // (1) ստեղծել
  alert( "Ողջույն" );
};

let func = sayHi;  //(2)
// ...

Ամեն ինչ նույն կերպ կաշխատի:

Կարող եք զարմանալ, թե ինչո՞ւ Ֆունկցիոնալ Արտահայտություններն ունեն կետ-ստորակետ `;` վերջում, իսկ Ֆունկցիոնալ Հռչակագրերը չունեն.

```js
function sayHi() {
  // ...
}

let sayHi = function() {
  // ...
}*!*;*/!*
```

Պատասխանը պարզ է. Ֆունկցիոնալ Արտահայտությունն այստեղ որպես `function(…) {…}` ստեղծվել է վերագրման դրույթի ներսում. `let sayHi = …;` (statement): Կետ-ստորակետը `;` խորհուրդ է տրվում դնել դրույթի վերջում, դա ֆունկցիայի շարահյուսության մաս չէ:

Կետ-ստորակետը կարող է լինել այդտեղ ավելի պարզ վերագրման համար, ինչպիսին է `let sayHi = 5;`, այն այդտեղ է նաև ֆունկցիա վերագրելու համար:

Հետկանչ ֆունկցիաներ

Դիտարկենք ֆունկցիաները որպես արժեքներ փոխանցելու և ֆունկցիոնալ արտահայտություններ օգտագործելու ավելի շատ օրինակներ:

Մենք կգրենք ֆունկցիա ask(question, yes, no) երեք պարամետրերով:

question : Հարցի տեքստը

yes : Գործարկման համար ֆունկցիա, եթե պատասխանը «Դրական» է

no : Գործարկման համար ֆունկցիա, եթե պատասխանը «Բացասական» է

Ֆունկցիան պետք է հարց տա question այնուհետև, կախված օգտատիրոջ պատասխանից, կանչի yes() կամ no().

*!*
function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}
*/!*

function showOk() {
  alert( "Դուք համաձայնեցիք:" );
}

function showCancel() {
  alert( "Դուք չեղարկեցիք գործարկումը։" );
}

// օգտագործումը. showOk և showCancel ֆունկցիաները փոխանցվում են ask ֆունկցիային որպես արգումենտներ
ask("Դուք համաձա՞յն եք:", showOk, showCancel);

Գործնականում նման ֆունկցիաները բավականին օգտակար են: Հիմնական տարբերությունը «իրական կյանքով» ask-ի և վերոնշյալ օրինակի միջև այն է, որ «իրական կյանքով» ֆունկցիաները օգտագործում են ավելի բարդ ուղիներ օգտատիրոջ հետ փոխազդելու համար, քան պարզ confirm-ը: Բրաուզերում նման ֆունկցիաները սովորաբար նկարում են գեղեցիկ տեսք ունեցող հարցերի պատուհան: Բայց դա այլ պատմություն է:

ask ֆունկցիայի showOk և showCancel արգումենտները կոչվում են callback functions (հետկանչ ֆունկցիաներ) կամ պարզապես callbacks (հետկանչեր):

Գաղափարն այն է, որ մենք փոխանցում ենք ֆունկցիա և ակնկալում, որ այն հետագայում «հետ կկանչվի» անհրաժեշտության դեպքում: Մեր պարագայում showOk-ը դառնում է հետկանչ «դրական» պատասխանի համար, իսկ showCancel-ը՝ «բացասական» պատասխանի համար:

Մենք կարող ենք օգտագործել Ֆունկցիոնալ Արտահայտություններ՝ նույն ֆունկցիան ավելի հակիրճ գրելու համար.

function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

*!*
ask(
  "Դուք համաձա՞յն եք:",
  function() { alert("Դուք համաձայնեցիք:"); },
  function() { alert("Դուք չեղարկեցիք գործարկումը։"); }
);
*/!*

Այստեղ ֆունկցիաները ճշգրիտ են հռչակված ask(...) կանչի ներսում: Նրանք չունեն անվանում, ուստի կոչվում են anonymous (անանուն): Նման ֆունկցիաները հասանելի չեն ask-ից դուրս (քանի որ դրանք վերագրված չեն փոփոխականների), բայց դա հենց այն է, ինչ մենք ուզում ենք այստեղ:

Շատ բնական է, որ նմանատիպ կոդ է հայտնվում մեր սքրիփթներում, այն JavaScript-ի ոգով է:

Սովորական արժեքները, ինչպիսիք են տողերը կամ թվերը, ներկայացնում են *տվյալներ*:

Ֆունկցիան կարող է ընկալվել որպես *գործողություն*։

Մենք կարող ենք այն փոխանցել փոփոխականների միջև և գործարկել` երբ կցանկանանք:

Ֆունկցիոնալ Արտահայտությունն ընդդեմ Ֆունկցիոնալ Հռչակագրի

Եկեք ձևակերպենք Ֆունկցիոնալ Հռչակագրի և Արտահայտության միջև հիմնական տարբերությունները:

Առաջինը՝ շարահյությություն. ինչպես տարանջատել դրանք կոդում:

  • Ֆունկցիոնալ Հռչակագիր (Function Declaration). ֆունկցիա՝ հայտարարված որպես առանձին դրույթ (statement) հիմնական կոդի հոսքում:

    // Ֆունկցիոնալ Հռչակագիր
    function sum(a, b) {
      return a + b;
    }
  • Ֆունկցիոնալ Արտահայտություն (Function Expression). ֆունկցիա՝ ստեղծված արտահայտության կամ մեկ այլ շարահյուսական կառուցվածքի ներսում: Այստեղ ֆունկցիան ստեղծվում է «վերագրման արտահայտության» = աջ կողմում.

    // Ֆունկցիոնալ Արտահայտություն
    let sum = function(a, b) {
      return a + b;
    };

Ավելի նուրբ տարբերությունն այն է, թե երբ է ֆունկցիան ստեղծվում JavaScript շարժիչի կողմից:

Ֆունկցիոնալ Արտահայտությունը ստեղծվում է, երբ կատարումը հասնում է դրան և կիրառելի է միայն այդ պահից:

Երբ կատարման հոսքն անցնում է վերագրման աջ կողմ let sum = function…, այդ պահից սկսած ֆունկցիան համարվում է ստեղծված և կարող է օգտագործվել (վերագրվել, կանչվել, և այլն․․․):

Ֆունկցիոնալ Հռչակագրերը տարբեր են:

Ֆունկցիոնալ Հռչակագիրը կարող է կանչվել ավելի վաղ, քան այն սահմանվել է:

Օրինակ՝ գլոբալ Ֆունկցիոնալ Հռչակագիրը հասանելի է ամբողջ սքրիփթում, անկախ նրանից, թե որտեղ է այն գտնվում:

Դա պայմանավորված է ներքին ալգորիթմներով: Երբ JavaScript-ը պատրաստվում է գործարկել սքրիփթը, այն նախ որոնում է գլոբալ Ֆունկցիոնալ Հռչակագրեր դրանում և ստեղծում ֆունկցիաներ: Մենք կարող ենք դա համարել որպես «նախաձեռնման փուլ»:

ԵՎ այն բանից հետո, երբ բոլոր Ֆունկցիոնալ Հռչակագրերը մշակվել են, կոդը կատարվում է: Այսպիսով, այն ունի հասանելիություն այս ֆունկցիաներին:

Օրինակի համար սա աշխատում է.

*!*
sayHi("Պողոս"); // Ողջույն Պողոս
*/!*

function sayHi(name) {
  alert( `Ողջույն ${name}` );
}

Ֆունկցիոնալ Հռչակագիրը sayHi ստեղծվում է, երբ JavaScript-ը պատրաստվում է սկսել սքրիփթը և դրա մեջ ամենուր տեսանելի է այդ ֆունկցիան:

...Եթե դա լիներ Ֆունկցիոնալ Արտահայտություն, ապա այն չէր աշխատի.

*!*
sayHi("Պողոս"); // սխալ
*/!*

let sayHi = function(name) {  // (*) այլևս ոչ մի կախարդանք
  alert( `Ողջույն ${name}` );
};

Ֆունկցիոնալ Արտահայտությունները ստեղծվում են, երբ կատարումը հասնում է դրանց: Դա տեղի կունենա միայն (*) տողում։ Չափազանց ուշ։

Ֆունկցիոնալ Արտահայտությունների մեկ այլ առանձնահատկություն է դրանց բլոկային տեսադաշտը։

Խիստ ռեժիմում, երբ Ֆունկցիոնալ Հռչակագիրը գտնվում է կոդի բլոկի ներսում, այն տեսանելի է ամենուր՝ այդ բլոկի ներսում, բայց ոչ՝ դրանից դուրս:

Օրինակի համար եկեք պատկերացնենք, որ մենք պետք է հռչակենք welcome() ֆունկցիան՝ կախված age փոփոխականից, որը մենք ստանում ենք գործարկման ընթացքում: Եվ հետո մենք պլանավորում ենք օգտագործել այն որոշ ժամանակ անց:

Եթե մենք օգտագործում ենք Ֆունկցիոնալ Հռչակագիր, այն չի աշխատի այնպես, ինչպես նախատեսված էր.

let age = prompt("Քանի՞ տարեկան եք:", 18);

// պայմանականորեն հռչակել ֆունկցիա
if (age < 18) {

  function welcome() {
    alert("Ողջույն");
  }

} else {

  function welcome() {
    alert("Ողջույններ");
  }

}

// ...օգտագործել ավելի ուշ
*!*
welcome(); // սխալ` welcome is not defined
*/!*

Դա պայմանավորված է նրանով, որ Ֆունկցիոնալ Հռչակագիրը տեսանելի է միայն այն կոդի բլոկի ներսում, որտեղ այն գտնվում է:

Ահա ևս մեկ օրինակ.

let age = 16; // օրինակի համար վերցրեք 16

if (age < 18) {
*!*
  welcome();                // \   (գործարկվում է)
*/!*
                            //  |
  function welcome() {      //  |
    alert("Ողջույն");       //  |  Ֆունկցիոնալ Հռչակագիրը հասանելի է
  }                         //  |  ամենուր՝ բլոկում, որտեղ այն հայտարարված է
                            //  |
*!*
  welcome();                // /   (գործարկվում է)
*/!*

} else {

  function welcome() {    
    alert("Ողջույններ");
  }
}

// Այստեղ մենք ձևավոր փակագծերից դուրս ենք,
// այնպես որ մենք չենք կարող տեսնել դրանց ներսում ստեղծված Ֆունկցիոնալ Հռչակագրերը:

*!*
welcome(); // սխալ՝ welcome is not defined
*/!*

Ի՞նչ կարող ենք անել, որպեսզի welcome-ը դարձնենք տեսանելի if-ից դուրս:

Ճիշտ մոտեցումը կլինի՝ օգտագործել Ֆունկցիոնալ Արտահայտություն և վերագրել welcome-ը փոփոխականի, որը հռչակված է if-ից դուրս և ունի համապատասխան տեսանելիություն:

Այս կոդը աշխատում է այնպես, ինչպես նախատեսված է.

let age = prompt("Քանի՞ տարեկան եք:", 18);

let welcome;

if (age < 18) {

  welcome = function() {
    alert("Ողջույն");
  };

} else {

  welcome = function() {
    alert("Ողջույններ");
  };

}

*!*
welcome(); // այժմ նորմալ է
*/!*

Կամ մենք կարող ենք այն էլ ավելի պարզեցնել՝ օգտագործելով ? հարցական նշանի օպերատոր.

let age = prompt("Քանի՞ տարեկան եք:", 18);

let welcome = (age < 18) ?
  function() { alert("Ողջույն"); } :
  function() { alert("Ողջույններ"); };

*!*
welcome(); // այժմ նորմալ է
*/!*
Որպես հիմնական կանոն, երբ մենք պետք է հայտարարենք ֆունկցիա, առաջին հերթին պետք է հաշվի առնել Ֆունկցիոնալ Հռչակագրի շարահուսությունը: Այն ավելի շատ ազատություն է տալիս այն հարցում, թի ինչպես կազմակերպենք մեր կոդը, քանի որ մենք կարող ենք կանչել այդպիսի ֆունկցիաները նախքան նրանց հռչակումը:

Դա նաև ավելի ընթեռնելի է, քանի որ ավելի հեշտ է փնտրել `function f(…) {…}` կոդում, քան՝ `let f = function(…) {…};`: Ֆունկցիոնալ Հռչակագրերն ավելի «գրավիչ են աչքի համար»:

...Բայց եթե Ֆունկցիոնալ Հռչակագիրն ինչ-ինչ պատճառներով մեզ չի համապատասխանում, կամ մեզ անհրաժեշտ է պայմանական հայտարարագիր (մենք հենց նոր տեսանք օրինակը), ապա պետք է օգտագործվի Ֆունկցիոնալ Արտահայտություն:

Ամփոփում

  • Ֆունկցիաներն արժեքներ են: Դրանք կարող են վերագրվել, պատճենվել կամ հռչակվել կոդի ցանկացած վայրում:
  • Եթե հիմնական կոդի հոսքում ֆունկցիան հռչակվում է որպես առանձին դրույթ, դա կոչվում է «Ֆունկցիոնալ Հռչակագիր» (Function Declaration):
  • Եթե ֆունկցիան ստեղծվում է որպես արտահայտության մաս, այն կոչվում է «Ֆունկցիոնալ Արտահայտություն» (Function Expression):
  • Ֆունկցիոնալ Հռչակագրերը մշակվում են նախքան կոդի բլոկի գործարկումը: Դրանք բլոկում տեսանելի են ամենուր:
  • Ֆունկցիոնալ Արտահայտությունները ստեղծվում են, երբ կատարողական հոսքը հասնում է դրանց:

Շատ դեպքերում, երբ մենք պետք է հռչակենք ֆունկցիա, գերադասելի է Ֆունկցիոնալ Հռչակագիր, քանի որ այն տեսանելի է նախքան իր հռչակումը: Դա մեզ ավելի շատ ճկունություն է տալիս կոդի կազմակերպման հարցում և սովորաբար ավելի ընթեռնելի է:

Այսպիսով, մենք պետք է օգտագործենք Ֆունկցիոնալ Արտահայտություն միայն այն դեպքում, երբ Ֆունկցիոնալ Հռչակագիրը հարմար չէ առաջադրանքի համար: Մենք տեսել ենք դրա մի քանի օրինակ այս գլխում և ավելին կտեսնենք հետագայում: