Kako funkcioniraju blokatori javascripta?

Kako biste objasnili zatvaranje JavaScripta za nekoga tko poznaje koncepte od kojih su sastavljeni (na primjer, funkcije, varijable, itd.), Ali ne razumiju sami zatvaranje?

Vidio sam primjer sheme iz Wikipedije, ali, nažalost, nije pomogao.

7654
21 сент. postavljen na e-satis 21. rujna. 2008-09-21 17:12 '08 u 17:12 2008-09-21 17:12
@ 89 odgovora
  • 1
  • 2
  • 3

Zatvaranje javascripta za početnike

Poslao Morris on Tue, 2006-02-21 10:19. Zajednica je od tada uređena.

Zatvaranje nije magija

Ova stranica objašnjava zatvaranje tako da ih programer može razumjeti - koristeći radni JavaScript kôd. Ovo nije za gurue ili funkcionalne programere.

Zatvaranje nije teško razumjeti čim se zašije osnovni koncept. Međutim, oni se ne mogu razumjeti čitanjem teorijskih ili akademski utemeljenih objašnjenja!

Ovaj je članak namijenjen programerima s nekim osnovnim iskustvom u programiranju i može čitati sljedeću funkciju JavaScripta:

prvoklasnih značajki ;  je izraz koji se može odnositi na varijable unutar njegovog opsega (kada je prethodno bio deklariran), biti dodijeljen varijabli, proslijeđen kao argument funkcije ili vraćen kao rezultat funkcije. 

Primjer zatvaranja

Sljedeći kod vraća referencu funkcije:

 function say667() { // Local variable that ends up within closure var num = 42; var say = function() { console.log(num); } num++; return say; } var sayNumber = say667(); sayNumber(); // logs 43 

Primjer 4

Sve tri globalne funkcije imaju zajedničku referencu na istu blizinu, jer su sve one deklarirane tijekom jednog poziva setupSomeGlobals() .

 function sayAlice() { var say = function() { console.log(alice); } // Local variable that ends up within closure var alice = 'Hello Alice'; return say; } sayAlice()();// logs "Hello Alice" 

Tricky: također imajte na umu, say varijabla say također unutar zatvarača, i može sayAlice() bilo koju drugu funkciju koja se može deklarirati u sayAlice() , ili se može dobiti rekurzivno unutar unutarnje funkcije.

Primjer 6

Ovo je prava čarolija za sve ljude, tako da je morate razumjeti. Budite vrlo oprezni ako definirate funkciju unutar petlje: lokalne varijable iz zatvaranja možda neće djelovati kao što možda mislite.

Morate razumjeti funkciju javascript "varijabla podizanja" kako biste razumjeli ovaj primjer.

 function newClosure(someNum, someRef) { // Local variables that end up within closure var num = someNum; var anArray = [1,2,3]; var ref = someRef; return function(x) { num += x; anArray.push(num); console.log('num: ' + num + '; anArray: ' + anArray.toString() + '; ref.someVar: ' + ref.someVar + ';'); } } obj = {someVar: 4}; fn1 = newClosure(4, obj); fn2 = newClosure(5, obj); fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4; fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4; obj.someVar++; fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5; fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5; 

rezime

Ako sve izgleda potpuno nejasno, najbolje je igrati se s primjerima. Čitanje objašnjenja mnogo je teže od razumijevanja primjera. Moja objašnjenja za zatvaranje i okvire stogova, itd. Oni nisu tehnički ispravni - to su gruba pojednostavljenja osmišljena da pomognu razumjeti. Nakon što je osnovna ideja riješena, detalje možete dobiti kasnije.

Krajnje točke:

  • Kad god koristite function unutar druge funkcije, koristi se zatvaranje.
  • Kad god koristite funkciju eval() unutar funkcije, koristi se zatvaranje. Tekst koji možete eval može se odnositi na lokalne varijable funkcije, au eval možete stvoriti nove lokalne varijable s eval('var foo = …')
  • Kada koristite new Function(…) ( konstruktor funkcije ) unutar funkcije, ona ne stvara zatvor. (Nova funkcija ne može se odnositi na lokalne varijable vanjske funkcije.)
  • Zatvaranje u JavaScriptu je kao čuvanje kopije svih lokalnih varijabli, baš kao i prilikom izlaska iz funkcije.
  • Vjerojatno je najbolje misliti da je zatvaranje uvijek kreirano kao unos funkcije, a lokalne su varijable dodane ovom zatvaranju.
  • Novi skup lokalnih varijabli se sprema svaki put kada se funkcija nazove s zatvaranjem (s obzirom da funkcija sadrži deklaraciju funkcije unutar nje, ili se referenca na ovu internu funkciju ili vraća ili je vanjska referenca na neki način pohranjena za nju).
  • Dvije funkcije mogu izgledati kao da imaju isti izvorni kod, ali imaju potpuno drugačije ponašanje zbog skrivenog zatvaranja. Mislim da JavaScript kôd ne može stvarno otkriti ima li funkcija zatvaranje veze ili ne.
  • Ako pokušate izvršiti bilo kakve promjene u dinamičkom izvornom kodu (na primjer: myFunction = Function(myFunction.toString().replace(/Hello/,'Hola')); ), neće raditi ako je myFunction završno (naravno, ne biste razmišljali o zamjeni izvornih linija tijekom izvođenja, ali ...).
  • Izjave funkcija možete dobiti unutar deklaracija funkcija unutar funkcija mdash, a zatvaranje možete dobiti na više od jedne razine.
  • Mislim da je obično zatvaranje pojam i za funkciju i za zarobljene varijable. Napominjemo da ovu odredbu ne koristim u ovom članku!
  • Pretpostavljam da su zatvaranja JavaScripta različita od onih koja se obično nalaze u funkcionalnim jezicima.

komunikacija

zahvaljujući

Ako ste upravo saznali za zatvaranje (ovdje ili negdje drugdje!), Onda sam zainteresiran za bilo kakve povratne informacije od vas o bilo kakvim promjenama koje možete predložiti da ovaj članak bude jasniji. Pošalji poruku morrisjohns.com (morris_closure @). Imajte na umu da ja nisam JavaScript guru - ne na kraju.


Izvorni post Morrisa može se naći u internetskoj arhivi .

6329
21 сент. odgovor je dao Joel Anair 21 sep . 2008-09-21 17:18 '08 u 17:18 2008-09-21 17:18

Kad god vidite ključnu riječ funkcije u drugoj funkciji, interna funkcija ima pristup varijablama u vanjskoj funkciji.

 function foo(x) { var tmp = 3; return function (y) { console.log(x + y + (++tmp)); // will also log 16 } } var bar = foo(2); // bar is now a closure. bar(10); 

Gore navedena funkcija također će napisati 16, jer bar se još uvijek može odnositi na x i tmp , čak i ako više nije unutar regije.

Međutim, budući da tmp dalje visi oko zatvaranja unutarnje bar , ona se također povećava. Povećat će se svaki put kada nazovete bar .

Najjednostavniji primjer zatvaranja je sljedeći:

border=0

 function foo(x) { var tmp = 3; return function (y) { console.log(x + y + tmp); x.memb = x.memb ? x.memb + 1 : 1; console.log(x.memb); } } var age = new Number(2); var bar = foo(age); // bar is now a closure referencing age. bar(10); 

Kao što se i očekivalo, svaki poziv na bar(10) će povećati x.memb . Ne možete očekivati ​​da se x jednostavno odnosi na isti objekt kao i na age varijablu! Nakon nekoliko poziva na bar age.memb će biti 2! Ova veza služi kao osnova za curenje memorije s HTML objektima.

3825
21 сент. odgovor dao Ali na 21. rujna. 2008-09-21 18:16 '08 u 18:16 2008-09-21 18:16

PREDGOVOR: ovaj odgovor je napisan kada je pitanje bilo:

Kao stari Albert, rekao je: "Ako to ne možete objasniti šestogodišnjem djetetu, vi sami ne razumijete." Pa, pokušao sam objasniti zatvaranje JS-a 27-godišnjem prijatelju i to je potpuno propalo.

Može li itko pomisliti da sam ja šestogodišnjak, i čudno zainteresiran za ovo pitanje?

Prilično sam siguran da sam bio jedan od onih ljudi koji su pokušali doslovno uzeti početno pitanje. Od tada je ovo pitanje nekoliko puta mutiralo, pa se moj odgovor sada može činiti nevjerojatno glupim i neprikladnim. Nadam se da opća ideja ove priče ostaje zanimljiva.


Ja sam veliki obožavatelj analogija i metafora u objašnjavanju složenih pojmova, pa dopustite da se okušam u povijesti.

Jednom davno:

Bila je princeza ...

 function princess() { 

Živjela je u predivnom svijetu punom pustolovina. Upoznala je svog princa Charlesa, jahala oko svoga svijeta na jednoroga, borila se s zmajevima, susrela se s govornim životinjama i mnogim drugim fantastičnim stvarima.

  var adventures = []; function princeCharming() {  } var unicorn = {  }, dragons = [  ], squirrel = "Hello!";  

Ali uvijek se morala vraćati svom dosadnom svijetu nevolja i odraslih.

  return { 

I često im je pričala o svojoj zadnjoj zadivljujućoj avanturi kao princezi.

  story: function() { return adventures[adventures.length - 1]; } }; } 

Ali sve što su vidjeli bila je djevojčica ...

 var littleGirl = princess(); 

... priča priče o magiji i fantaziji.

 littleGirl.story(); 

I dok su odrasli znali za prave princeze, nikada ne bi povjerovali u jednoroge ili zmajeve, jer ih nikad nisu vidjeli. Odrasli su rekli da postoje samo u mašti djevojčice.

Ali mi znamo pravu istinu; da djevojčica s princezom unutra ...

... zapravo princeza s djevojčicom unutra.

2273
24 июня '11 в 21:49 2011-06-24 21:49 odgovor je dao Jacob Swartwood 24. lipnja '11 u 21:49 2011-06-24 21:49

Uzimajući ovo pitanje ozbiljno, moramo saznati da je tipična šestogodišnja osoba kognitivno sposobna, iako je priznato da oni koji su zainteresirani za JavaScript nisu tako tipični.

O razvoju djetinjstva: od 5 do 7 godina se kaže:

Vaše dijete će moći pratiti upute u dva koraka. Na primjer, ako svom djetetu kažete: "Idite u kuhinju i uzmite vreću za smeće", sjećaju se tog smjera.

Ovaj primjer možemo upotrijebiti za objašnjenje zatvaranja na sljedeći način:

Kuhinja je blizina u kojoj se nalazi lokalna varijabla koja se zove trashBags . Unutar kuhinje nalazi se funkcija getTrashBag koja prima jednu vreću za smeće i vraća je.

To možemo kodirati u javascript kako slijedi:

696
02 сент. odgovor je dan dlaliberte 02 sep . 2011-09-02 18:23 '11 u 18:23 2011-09-02 18:23

Slameni čovjek

Moram znati koliko puta je gumb pritisnut i učinite nešto na svaki treći klik ...

Prilično očigledno rješenje

 <button id="button">Click Me!</button> 

Теперь это будет работать, но оно вторгается во внешнюю область, добавляя переменную, единственной целью которой является отслеживание счета. В некоторых ситуациях это было бы предпочтительнее, так как вашему внешнему приложению может потребоваться доступ к этой информации. Но в этом случае мы меняем только каждый третий клик, поэтому рекомендуется включать эту функциональность внутри обработчика событий .

Рассмотрим этот вариант

 <button id="button">Click Me!</button>