Aizvērumi JavaScript paskaidrojumā ar piemēriem

Kas ir slēgšana?

Aizvēršana ir funkcijas un leksiskās vides (darbības jomas) kombinācija, kurā šī funkcija tika deklarēta. Aizvēršana ir būtisks un spēcīgs Javascript īpašums. Šajā rakstā ir aplūkoti aizvērumu jautājumi par to, kā un kāpēc?

Piemērs

//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

Vēl viens piemērs

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 } ]

Slēgšana “atceras” vidi, kurā tā tika izveidota. Šī vide sastāv no visiem lokālajiem mainīgajiem lielumiem, kas slēgšanas izveidošanas laikā bija piemērojami.

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 

Aizvēršana ir noderīga, jo tā ļauj “atcerēties” datus un pēc tam ļauj darboties ar šiem datiem, izmantojot atgrieztās funkcijas. Tas ļauj javascript atdarināt citas programmēšanas valodās atrodamas privātas metodes. Privātās metodes ir noderīgas, lai ierobežotu piekļuvi kodam, kā arī pārvaldītu globālo nosaukumvietu.

Privātie mainīgie un metodes

Slēgumus var izmantot arī, lai iekapsulētu privātos datus / metodes. Apskatiet šo piemēru:

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

Šajā piemērā mēs nevarēsim piekļūt balanceno jebkuras vietas ārpus bankAccountfunkcijas, tas nozīmē, ka mēs tikko esam izveidojuši privātu mainīgo. Kur ir slēgšana? Nu padomājiet par to, kas bankAccount()atgriežas. Tas faktiski atgriež objektu ar virkni funkciju tajā, un tomēr, kad mēs piezvanām account.getBalance(), funkcija spēj “atcerēties” savu sākotnējo atsauci balance. Tas ir slēgšanas spēks, kad funkcija “atceras” savu leksisko darbības jomu (sastādīt laika tvērumu), pat ja funkcija tiek izpildīta ārpus šīs leksiskās darbības sfēras.

Bloka diapazona mainīgo atdarināšana.

Javascript nepastāvēja ar blokiem saistītu mainīgo jēdziens. Tas nozīmē, ka, definējot mainīgo, piemēram, priekšējā daļā, šis mainīgais ir redzams arī ārpus priekšējās daļas. Tātad, kā slēgšana var palīdzēt mums atrisināt šo problēmu? Apskatīsim.

 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 }

Tā kā mainīgajam i nav bloķēšanas jomas, tā vērtība visās trīs funkcijās tika atjaunināta ar cilpas skaitītāju un izveidoja ļaunprātīgas vērtības. Aizvēršana var palīdzēt mums atrisināt šo problēmu, izveidojot momentuzņēmumu par vidi, kurā funkcija bija tās izveidošanas laikā, saglabājot tās stāvokli.

 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 }

Javascript es6 + vēlīnās versijās ir jauns atslēgvārds ar nosaukumu let, kuru var izmantot, lai mainīgajam piešķirtu bloku kopu. Ir arī daudzas funkcijas (forEach) un visas bibliotēkas (lodash.js), kas ir veltītas tādu problēmu risināšanai kā iepriekš paskaidrots. Tie noteikti var palielināt jūsu produktivitāti, tomēr, mēģinot radīt kaut ko lielu, joprojām ir ārkārtīgi svarīgi zināt zināšanas par visiem šiem jautājumiem.

Aizvēršanai ir daudz īpašu lietojumprogrammu, kas ir noderīgas, veidojot lielas javascript programmas.

  1. Privātu mainīgo atdarināšana vai iekapsulēšana
  2. Asinhrono servera puses zvanu veikšana
  3. Bloka mēroga mainīgā izveidošana.

Privātu mainīgo atdarināšana.

Atšķirībā no daudzām citām valodām Javascript nav mehānisma, kas ļautu objektā izveidot iekapsulētus instances mainīgos. Veidojot vidējas vai lielas programmas, var būt daudz problēmu ar publiskas instances mainīgajiem lielumiem. Tomēr ar slēgšanu šo problēmu var mazināt.

Līdzīgi kā iepriekšējā piemērā, jūs varat izveidot funkcijas, kas atgriež objektu literāļus ar metodēm, kurām ir piekļuve objekta lokālajiem mainīgajiem, tos neatklājot. Tādējādi padarot tos faktiski privātus.

Aizvēršana var arī palīdzēt pārvaldīt globālo nosaukumvietu, lai izvairītos no sadursmēm ar globāli koplietotiem datiem. Parasti visi globālie mainīgie tiek koplietoti starp visiem jūsu projekta skriptiem, kas noteikti sagādās daudz nepatikšanas, veidojot vidējas vai lielas programmas. Tāpēc bibliotēku un moduļu autori izmanto slēgšanu, lai paslēptu visa moduļa metodes un datus. To sauc par moduļa modeli, tas izmanto uzreiz izsauktu funkciju izteiksmi, kas eksportē tikai noteiktu funkcionalitāti uz ārpasauli, ievērojami samazinot globālo atsauču daudzumu.

Šeit ir īss moduļa skeleta paraugs.

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

Aizvēršana ir noderīga, lai iegūtu jaunus privāto mainīgo gadījumus, kas atrodas vidē “atcerējās”, un šiem mainīgajiem var piekļūt, tikai izmantojot atgriezto funkciju vai metodes.

Vektori

Vektors, iespējams, ir vienkāršākais kolekcijas veids Clojure. Jūs varat domāt par to kā masīvu Javascript. Definēsim vienkāršu vektoru:

(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])

Jūs redzēsiet, ka tas izmanto kvadrātiekavas, tāpat kā masīvs JS. Tā kā Clojure, tāpat kā JS, tiek ierakstīts dinamiski, vektori var saturēt jebkura veida elementus, ieskaitot citus vektorus.

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

Vienumu pievienošana vektoram

Izmantojot elementu, varat pievienot vienumus vektoram conj. Varat arī izveidot sarakstu, izmantojot into, bet ņemiet vērā, ka tas intoir paredzēts divu vektoru apvienošanai, tāpēc abiem tā argumentiem jābūt vektoriem, un izmantošana intoir lēnāka nekā izmantošana 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]
: raķete:

IDEO viens!

Vienumu izgūšana no 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?

Vektors ir jāizmanto gandrīz visos gadījumos, ja jums nepieciešama kolekcija, jo tiem ir īsākais brīvpiekļuves laiks, kas atvieglo vienumu iegūšanu no vektora. Ņemiet vērā, ka vektori ir sakārtoti. Ja pasūtījumam nav nozīmes, var būt labāk izmantot komplektu. Ņemiet vērā arī to, ka vektori ir paredzēti priekšmetu pievienošanai; ja jums ir jāpievieno vienumi, ieteicams izmantot sarakstu.

Plašāka informācija par slēgšanu:

  • Uzziniet JavaScript slēgšanu sešās minūtēs
  • Pamata ceļvedis par aizvēršanu JavaScript
  • Atklājiet slēgšanas iespējas VueJS
  • JavaScript slēgšana izskaidrojama ar pakas nosūtīšanu pa pastu