Javascript engelleyicileri nasıl çalışır?

Oluşturuldukları kavramları bilen (örneğin, fonksiyonlar, değişkenler, vb.) Ancak kapanışların kendilerini anlamayan birisinin JavaScript'in kapatılmasını nasıl açıklarsınız?

Vikipedi'de verilen şemadan bir örnek gördüm, fakat ne yazık ki yardımcı olmadı.

7654
21 сент. 21 eylülde e-satis olarak ayarlandı . 2008-09-21 17:12 '08, 17:12, 2008-09-21 17:12
@ 89 cevaplar
  • 1
  • 2
  • 3

Yeni başlayanlar için javascript kapatılıyor

Morris tarafından Tue, 2006-02-21 10:19 tarihinde sunulmuştur. Topluluk o zamandan beri düzenlendi.

Kapanış sihir değildir

Bu sayfa kapanışı açıklar, böylece çalışan JavaScript kodunu kullanarak programcının bunları anlayabilmesini sağlar. Bu, guru veya işlevsel programcılar için değildir.

Temel kavram dikilir kapanmaz anlaşılması zor değildir. Ancak, teorik veya akademik temelli açıklamaları okuyarak anlaşılamazlar!

Bu makale, bazı temel programlama deneyimine sahip programcılar için hazırlanmıştır ve aşağıdaki JavaScript işlevini okuyabilir:

birinci sınıf özellikleri desteklemenin bir yoludur;  kapsamındaki değişkenlere (daha önce bildirildiğinde) atıfta bulunabilen, bir değişkene atanabilen, işlev bağımsız değişkeni olarak iletilen veya bir işlev sonucu döndürülen bir ifadedir. 

Kapanış örneği

Aşağıdaki kod bir fonksiyon referansı döndürür:

 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 

Örnek 4

Üç global fonksiyonun da aynı kapanış için ortak bir referansı vardır, çünkü hepsi tek bir setupSomeGlobals() sırasında setupSomeGlobals() bildirilir.

 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: ayrıca şunu say değişkeni kapağın içinde de olduğunu ve sayAlice() da sayAlice() da bildirilebilecek başka herhangi bir işlevi sayAlice() veya içsel bir işlev içinde yinelemeli olarak elde edilebilir.

Örnek 6

Bu, tüm insanlar için gerçek sihirdir, o yüzden anlaman gerekiyor. Bir döngü içindeki bir işlevi tanımlarsanız çok dikkatli olun: kapatmadan gelen yerel değişkenler ilk düşündüğünüz gibi davranmayabilir.

Bu örneği anlamak için javascript "değişken kaldırma" işlevini anlamanız gerekir.

 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; 

özet

Her şey tamamen belirsiz görünüyorsa, örneklerle oynamak en iyisidir. Açıklamaları okumak, örnekleri anlamaktan çok daha zor. Kapaklar ve yığın çerçeveleri vb. Hakkındaki açıklamalarım Teknik olarak doğru değiller - bunlar anlaşılmasına yardımcı olmak için tasarlanmış basitleştirmelerdir. Temel fikir çözüldükten sonra detayları daha sonra alabilirsiniz.

Bitiş noktaları:

  • function başka bir function içinde kullandığınızda, kapak kullanılır.
  • Bir fonksiyon içinde eval() kullandığınızda, bir close kullanılır. Değerlendirdiğiniz metin bir işlevin yerel değişkenlerine başvurabilir ve eval ile yeni yerel değişkenler bile oluşturabilirsiniz eval('var foo = …')
  • Bir işlevin içinde new Function(…) ( işlev yapıcısı ) kullandığınızda, bu bir kapanış oluşturmaz. (Yeni işlev, harici işlevin yerel değişkenlerini ifade edemez.)
  • JavaScript’te kapanmak, tıpkı bir işlevden çıktığınızda olduğu gibi tüm yerel değişkenlerin bir kopyasını tutmak gibidir.
  • Kapanmanın her zaman bir işlev girişi olarak oluşturulduğunu düşünmek en iyisidir ve bu kapamaya yerel değişkenler eklenir.
  • Bir fonksiyon kapatılması ile çağrıldığında, yeni bir yerel değişkenler kümesi kaydedilir (fonksiyonun içerisinde bir fonksiyon bildirimi olduğu veya bu dahili fonksiyona yapılan referansın geri gönderildiği veya harici referansın bir şekilde saklandığı).
  • İki işlev aynı kaynak koduna sahipmiş gibi görünebilir, ancak gizli kapatılmaları nedeniyle tamamen farklı bir davranışa sahip olabilir. JavaScript kodunun, işlevin bir bağlantı kapatması olup olmadığını gerçekten öğrenebileceğini sanmıyorum.
  • Dinamik kaynak kodunda herhangi bir değişiklik yapmaya çalışırsanız (örneğin: myFunction = Function(myFunction.toString().replace(/Hello/,'Hola')); ), eğer myFunction kapanıyorsa (elbette, siz çalışma zamanında kaynak satırlarını değiştirmeyi düşünmezsiniz, ama ...).
  • İşlev bildirimlerinin içindeki içindeki işlev bildirimlerini mdash işlevlerinin içinde bulabilir ve birden fazla seviyeye yaklaşabilirsiniz.
  • Genelde kapanmanın hem fonksiyon hem de yakalanan değişkenler için bir terim olduğunu düşünüyorum. Lütfen bu tanımı bu makalede kullanmadığımı unutmayın!
  • JavaScript'teki kapatmanın, işlevsel dillerde yaygın olanlardan farklı olduğundan şüpheleniyorum.

iletişim

sayesinde

Kapanmayı yeni öğrendiniz (burada veya başka bir yerde!), O zaman bu makaleyi daha net hale getirmek için önerebileceğiniz değişiklikler hakkında sizden herhangi bir geri bildirim almak istiyorum. Morrisjohns.com (morris_closure @) 'a bir mesaj gönderin. Lütfen bir JavaScript gurusu olmadığımı unutmayın - yakınlarda değil.


Orjinal Morris postu İnternet arşivinde bulunabilir .

6329
21 сент. Cevap Joel Anair tarafından 21 Eylül'de verilmiştir . 2008-09-21 17:18 '08, 17:18 2008-09-21 17:18

Function anahtar sözcüğünü başka bir işlevde gördüğünüzde, dahili işlev, harici işlevdeki değişkenlere erişebilir.

 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); 

Yukarıdaki fonksiyon da 16 yazacaktır, çünkü artık bölge içinde olmasa bile, bar hala x ve tmp başvurabilir.

Bununla birlikte, tmp hala iç bar kapanmasına dolandığından, aynı zamanda artmaktadır. Her bar aradığınızda artacaktır.

Bir kapanmanın en basit örneği şudur:

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); 

Beklendiği gibi, her bir bar(10) çağrısı x.memb . x age değişkeniyle aynı nesneye basitçe başvurmasını bekleyemezsiniz! age.memb için bir kaç çağrıdan sonra 2 olacak! Bu bağlantı, HTML nesnelerle yapılan bellek sızıntılarının temelini oluşturur.

3825
21 сент. 21 Eylül'de Ali'ye verilen cevap . 2008-09-21 18:16 '08, 18:16, 2008-09-21 18:16

ÖNSÖZ: Bu cevap, soru olduğunda yazılmıştır:

Yaşlı Albert gibi şöyle dedi: "Bunu altı yaşındaki bir çocuğa açıklayamazsanız, kendiniz bunu anlamıyorsunuz." JS'nin 27 yaşındaki bir arkadaşa kapandığını açıklamaya çalıştım ve tamamen başarısız oldum.

Biri 6 olduğumu ve garip bir şekilde bu konuya ilgi duyduğumu düşünebilir mi?

İlk soruyu kelimenin tam anlamıyla almaya çalışan insanlardan biri olduğuma eminim. O zamandan beri, bu soru birkaç kez değiştirildi, bu yüzden cevabım şimdi inanılmaz derecede aptal ve uygunsuz görünebilir. Umarım bu hikayenin genel fikri ilginçtir.


Karmaşık kavramları açıklamakta büyük bir analoji ve metafor hayranıyım, bu yüzden tarihte elimi deneyeyim.

Bir zamanlar:

Bir prenses vardı ...

 function princess() { 

Macera dolu harika bir dünyada yaşadı. Prensi Charles'la tanıştı, tek boynuzlu at üzerinde dünyayı gezdi, ejderhalarla savaştı, konuşan hayvanlar ve diğer birçok harika şeyle bir araya geldi.

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

Ama her zaman sıkıcı sıkıntı dünyasına ve yetişkinlere dönmek zorunda kaldı.

  return { 

Ve sık sık onlara bir prenses olarak son şaşırtıcı serüvenini anlattı.

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

Ama tek gördükleri küçük bir kızdı ...

 var littleGirl = princess(); 

... sihir ve fantezi hakkında hikayeler anlatıyor.

 littleGirl.story(); 

Ve yetişkinler gerçek prensesleri bilseler de, tek boynuzlu atlara veya ejderhalara asla inanmazlardı, çünkü onları hiç görmediler. Yetişkinler, yalnızca küçük bir kızın hayal gücü içinde var olduklarını söyledi.

Ama gerçek gerçeği biliyoruz; İçinde bir prenses olan küçük bir kız ...

... aslında içinde küçük bir kızın olduğu bir prenses.

2273
24 июня '11 в 21:49 2011-06-24 21:49 Cevap Jacob Swartwood tarafından 24 Haziran 11'de 21:49 2011-06-24 21:49 tarihinde verilmiştir.

Bu soruyu ciddiye alarak, 6 yaşındaki tipik bir kişinin bilişsel olarak yetenekli olduğunu bulmalıyız, ancak kuşkusuz, JavaScript ile ilgilenenlerin bu kadar tipik olmadıklarına rağmen.

Çocukluğun gelişimiyle ilgili olarak: 5-7 yıl arasında şöyle söylenir:

Çocuğunuz iki adımlı talimatları izleyebilecek. Örneğin, çocuğunuza şunları söylerseniz: "Mutfağa gidin ve bir çöp torbası alın", bu yönü hatırlayabilirler.

Bu örneği, kapanışları aşağıdaki gibi açıklamak için kullanabiliriz:

Bir mutfak, trashBags adı verilen yerel bir değişkenin olduğu trashBags . Mutfağın içinde bir çöp torbasını alan ve iade eden bir getTrashBag işlevi vardır.

Javascript'te bunu şu şekilde kodlayabiliriz:

696
02 сент. cevap dlaliberte 02 eylül verilir . 2011-09-02 18:23 '11 18:23 2011-09-02 18:23

Saman adam

Düğmeye kaç kez basıldığını bilmem ve her üç tıklatmada da bir şeyler yapmam gerekiyor ...

Oldukça açık bir çözüm

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

Bu şimdi işe yarayacak, ancak tek amacı hesabı izlemek olan bir değişken ekleyerek dış alanı işgal ediyor. В некоторых ситуациях это было бы предпочтительнее, так как вашему внешнему приложению может потребоваться доступ к этой информации. Но в этом случае мы меняем только каждый третий клик, поэтому рекомендуется включать эту функциональность внутри обработчика событий .

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

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