Uzávery v jazyku JavaScript sú vysvetlené v príkladoch

Čo sú uzávery?

Uzávierka je kombináciou funkcie a lexikálneho prostredia (rozsahu), v rámci ktorého bola táto funkcia deklarovaná. Uzávery sú základnou a silnou vlastnosťou Javascriptu. Tento článok pojednáva o tom, „ako“ a „prečo“ o uzáveroch:

Príklad

//we have an outer function named walk and an inner function named fly function walk (){ var dist = '1780 feet'; function fly(){ console.log('At '+dist); } return fly; } var flyFunc = walk(); //calling walk returns the fly function which is being assigned to flyFunc //you would expect that once the walk function above is run //you would think that JavaScript has gotten rid of the 'dist' var flyFunc(); //Logs out 'At 1780 feet' //but you still can use the function as above //this is the power of closures

Ďalší príklad

function by(propName) { return function(a, b) { return a[propName] - b[propName]; } } const person1 = {name: 'joe', height: 72}; const person2 = {name: 'rob', height: 70}; const person3 = {name: 'nicholas', height: 66}; const arr_ = [person1, person2, person3]; const arr_sorted = arr_.sort(by('height')); // [ { name: 'nicholas', height: 66 }, { name: 'rob', height: 70 },{ name: 'joe', height: 72 } ]

Záver si „pamätá“ prostredie, v ktorom bol vytvorený. Toto prostredie pozostáva z akýchkoľvek lokálnych premenných, ktoré boli v rozsahu v čase vytvorenia uzávierky.

function outside(num) { var rememberedVar = num; // In this example, rememberedVar is the lexical environment that the closure 'remembers' return function inside() { // This is the function which the closure 'remembers' console.log(rememberedVar) } } var remember1 = outside(7); // remember1 is now a closure which contains rememberedVar = 7 in its lexical environment, and //the function 'inside' var remember2 = outside(9); // remember2 is now a closure which contains rememberedVar = 9 in its lexical environment, and //the function 'inside' remember1(); // This now executes the function 'inside' which console.logs(rememberedVar) => 7 remember2(); // This now executes the function 'inside' which console.logs(rememberedVar) => 9 

Uzávery sú užitočné, pretože vám umožňujú „zapamätať si“ údaje a potom vám umožňujú pracovať s týmito údajmi prostredníctvom vrátených funkcií. Toto umožňuje javascriptu emulovať súkromné ​​metódy, ktoré sa nachádzajú v iných programovacích jazykoch. Súkromné ​​metódy sú užitočné na obmedzenie prístupu ku kódu a na správu vášho globálneho priestoru mien.

Súkromné ​​premenné a metódy

Uzávery možno použiť aj na zapuzdrenie súkromných údajov / metód. Zoznámte sa s týmto príkladom:

const bankAccount = (initialBalance) => { const balance = initialBalance; return { getBalance: function() { return balance; }, deposit: function(amount) { balance += amount; return balance; }, }; }; const account = bankAccount(100); account.getBalance(); // 100 account.deposit(10); // 110

V tomto príklade nebudeme mať prístup balanceodkiaľkoľvek mimo bankAccountfunkcie, čo znamená, že sme práve vytvorili súkromnú premennú. Kde je uzávierka? No, zamyslite sa nad tým, čo bankAccount()sa vracia. V skutočnosti vracia objekt s hromadou funkcií vo vnútri, a napriek tomu, keď voláme account.getBalance(), je funkcia schopná „zapamätať si“ svoj pôvodný odkaz balance. To je sila uzáveru, keď si funkcia „pamätá“ svoj lexikálny rozsah (rozsah kompilácie času), aj keď je funkcia vykonávaná mimo tohto lexikálneho rozsahu.

Emulácia premenných s blokovým rozsahom.

Javascript nemal koncept blokovaných premenných. To znamená, že napríklad pri definovaní premennej vo vnútri forloopu je táto premenná viditeľná aj zvonku forloop. Ako nám teda môžu uzávery pomôcť vyriešiť tento problém? Pozrime sa.

 var funcs = []; for(var i = 0; i < 3; i++){ funcs[i] = function(){ console.log('My value is ' + i); //creating three different functions with different param values. } } for(var j = 0; j < 3; j++){ funcs[j](); // My value is 3 // My value is 3 // My value is 3 }

Pretože premenná i nemá blokový rozsah, bola jej hodnota vo všetkých troch funkciách aktualizovaná počítadlom slučiek a vytvorená škodlivá hodnota. Uzávierka nám môže pomôcť vyriešiť tento problém vytvorením snímky prostredia, v ktorom sa funkcia nachádzala, keď bola vytvorená, so zachovaním jej stavu.

 var funcs = []; var createFunction = function(val){ return function() {console.log("My value: " + val);}; } for (var i = 0; i < 3; i++) { funcs[i] = createFunction(i); } for (var j = 0; j < 3; j++) { funcs[j](); // My value is 0 // My value is 1 // My value is 2 }

Neskoršie verzie JavaScriptu es6 + majú nové kľúčové slovo s názvom let, ktoré je možné použiť na to, aby sa premennej dal blockcope. Existuje tiež veľa funkcií (forEach) a celé knižnice (lodash.js), ktoré sú určené na riešenie problémov, ktoré sú vysvetlené vyššie. Určite môžu zvýšiť vašu produktivitu, je však nesmierne dôležité mať vedomosti o všetkých týchto problémoch pri pokuse o vytvorenie niečoho veľkého.

Uzávery majú veľa špeciálnych aplikácií, ktoré sú užitočné pri vytváraní veľkých Javascriptových programov.

  1. Emulácia súkromných premenných alebo zapuzdrenie
  2. Uskutočňovanie hovorov na strane asynchrónneho servera
  3. Vytvorenie premennej s blokovaným rozsahom.

Emulácia súkromných premenných.

Na rozdiel od mnohých iných jazykov nemá Javascript mechanizmus, ktorý vám umožňuje vytvárať zapuzdrené premenné inštancie v objekte. Mať premenné verejnej inštancie môže spôsobiť veľa problémov pri vytváraní stredných až veľkých programov. Tento problém sa však dá zmierniť uzáverami.

Rovnako ako v predchádzajúcom príklade, aj tu môžete vytvárať funkcie, ktoré vracajú objektové literály pomocou metód, ktoré majú prístup k lokálnym premenným objektu bez ich vystavenia. Teda urobiť ich skutočne súkromnými.

Uzávery vám tiež môžu pomôcť spravovať váš globálny menný priestor, aby ste sa vyhli kolíziám s globálne zdieľanými údajmi. Zvyčajne sú všetky globálne premenné zdieľané medzi všetkými skriptmi vo vašom projekte, čo vám pri vytváraní stredných až veľkých programov určite spôsobí veľa problémov. Preto autori knižníc a modulov používajú uzávery na skrytie metód a údajov celého modulu. Toto sa nazýva vzor modulu, používa okamžite vyvolaný funkčný výraz, ktorý exportuje iba určité funkcie do vonkajšieho sveta, čo výrazne znižuje množstvo globálnych referencií.

Tu je krátka ukážka kostry modulu.

var myModule = (function() = { let privateVariable = 'I am a private variable'; let method1 = function(){ console.log('I am method 1'); }; let method2 = function(){ console.log('I am method 2, ', privateVariable); }; return { method1: method1, method2: method2 } }()); myModule.method1(); // I am method 1 myModule.method2(); // I am method 2, I am a private variable

Uzávery sú užitočné na zachytenie nových inštancií súkromných premenných obsiahnutých v „zapamätanom“ prostredí a k týmto premenným je možné získať prístup iba prostredníctvom vrátenej funkcie alebo metód.

Vektory

Vektor je možno najjednoduchším typom zbierky v Clojure. V Javascript si to môžete predstaviť ako pole. Definujme jednoduchý vektor:

(def a-vector [1 2 3 4 5]) ;; Alternatively, use the vector function: (def another-vector (vector 1 2 3 4 5)) ;; You can use commas to separate items, since Clojure treats them as whitespace. (def comma-vector [1, 2, 3, 4, 5])

Uvidíte, že používa hranaté zátvorky, rovnako ako pole v JS. Pretože Clojure, podobne ako JS, je dynamicky typovaný, môžu vektory obsahovať prvky ľubovoľného typu vrátane iných vektorov.

(def mixed-type-vector [1 "foo" :bar ["spam" 22] #"^baz$"])

Pridávanie položiek do vektora

Položky môžete k vektoru pridať pomocou conj. Môžete tiež predponovať zoznam pomocou into, ale intoje to určené na zlúčenie dvoch vektorov, takže oba jeho argumenty musia byť vektory a použitie intoje pomalšie ako použitie conj.

(time (conj [1 2] 3)) ; => "Elapsed time: 0.032206 msecs" ; [1 2 3] (time (into [1] [2 3])) ; => "Elapsed time: 0.078499 msecs" ; [1 2 3]
: raketa:

IDEOne to!

Načítanie položiek z vektora

You can retrieve items from a vector using get. This is equivalent to using bracket notation to access items in an array in many imperative languages. Items in a vector are 0-indexed, counting from the left.

var arr = [1, 2, 3, 4, 5]; arr[0]; // => 1

In Clojure, this would be written like so:

(def a-vector [1 2 3 4 5]) (get a-vector 0) ; => 1

You can also give get a default value, if you give it an index that isn’t in the array.

;; the list doesn't have 2147483647 elements, so it'll return a string instead. (get a-vector 2147483646 "sorry, not found!") ; => "sorry, not found!"

Converting other collections into vectors

Non-vector data structures can be converted into vectors using the vec function. With hashmaps, this produces a 2D vector containing pairs of keys and values.

(vec '(1 2 3 4 5)) ; => [1 2 3 4 5] (vec {:jack "black" :barry "white"}) ; => [[:jack "black"] [:barry "white"]]

When to use a vector?

Vektor by sa mal použiť takmer vo všetkých prípadoch, ak potrebujete kolekciu, pretože majú najkratšie časy náhodného prístupu, čo uľahčuje načítanie položiek z vektora. Upozorňujeme, že vektory sú usporiadané. Ak na poradí nezáleží, môže byť lepšie použiť sadu. Upozorňujeme tiež, že vektory sú určené na pridávanie položiek; ak potrebujete predplatiť položky, môžete použiť zoznam.

Viac informácií o uzáveroch:

  • Naučte sa ukončenie JavaScriptu za šesť minút
  • Základný sprievodca uzávierkami v JavaScripte
  • Objavte silu uzáverov vo VueJS
  • Uzávery JavaScriptu vysvetlené odoslaním balíka