Js kapandı. Javascript'teki Devreler: Pratik Örnek, Özellikler ve Kurallar

Herkese merhaba! Bu yazıda bakacağız javascript'te bir kapatma nedir.

Bu oldukça basit bir konudur, ancak anlayışı gerektirir. İlk önce, işlevin içinde olanlara bakalım.

Fonksiyon tebrik (isim) (
// lexicalenvironment \u003d (İsim: "Nikolai", Metin: Tanımsız)
var metin \u003d "merhaba" + isim;
// lexicalenvironment \u003d (İsim: "Nikolai", Metin: "Merhaba, Nikolai")
Uyarı (metin);
}

Tebrik ("nikolai");

Burada ne oluyor ve ne Lexicalenvironment? Hadi çözelim.

İşlev çağrıldığında, bir nesne oluşturur LexicalenvironmentTüm yerel değişkenler ve fonksiyonların kaydedildiği ve dış kapsamın (daha sonra daha sonra) referansı. Bizim durumumuzda yerel bir değişken var İsim.hemen bir değeri (o zaman geçiyoruz) ve bu "Nikolai". Ancak yazdığım makalelerden birinde, söz çevirmeninin tüm değişkenlerle ilgili her şeyi bildiğini hatırlatıyorum. Bununla ilgili bu, işlevin başlangıcında zaten bir değişkeni var. mETİN., tercüman bunu bilir, ancak henüz bir tür değişkenin ödevine ulaşmadığı için, ona eşittir. tanımsız.. Şimdi değişken bir değer atarız ve nesnemiz Lexicalenvironment Değişiklikler. Mülkü mETİN. Kaydettiğimiz gerçeğine eşit hale gelir ("Merhaba, Nikolai" durumumuzda). İşlev çalışıldıktan sonra, nesne Lexicalenvironment Yok et. Sonraki çağrılarla, tekrar oluşturulacak vb.

Şimdi bir sonraki örneğe dönüyoruz. Bana bu durumda ne tür edilmeyeceğini söyle?

Var b \u003d 2;
X (a) işlevi (
Uyarı (A + B);
}
x (1);

Düşünce? En çok 3 numaranın gösterileceğini ve bu doğru cevap olduğunu düşünüyorum, ancak yorumunun değişken hakkında nasıl öğrendiğini söyleyebilirsin. b.? Sonuçta, vücut fonksiyonunda değil. Değilse, hadi anlayalım.

Aslında javascript. Denilen gizli bir özellik var [] . İşlev bildirildiğinde, her zaman bir yerde ilan edilir. Bu özellik başka bir işlevde olabilir, küresel bir nesnede olabilir. Bizim durumumuzda, fonksiyon küresel nesnede ilan edilir. pencere.Bu nedenle, mülk x. [] \u003d pencere.

Var b \u003d 2;
Fonksiyon x (a) (// x. [] \u003d Pencere
// lexicalenvironment \u003d (A: 1) -\u003e Pencere
Uyarı (A + B);
}
x (1);

Bu okun bir nesnesi var Lexicalenvironment - Bu, harici kapsamın bir referansıdır ve bu bağlantı özellik tarafından belirlenir. [] . Bu yüzden nesnede Lexicalenvironment Harici bir nesneye referans alacağız. pencere.. Tercüman bir değişken ararken, o zaman önce nesnede arar. LexicalenvironmentÖyleyse, bir değişken bulamadıysa, bağlantıya bakarsa, harici bir kapsama girer ve orada ve bu yüzden sonuna kadar arar. Herhangi bir yerde bu değişkeni bulamazsa, bir hata olacaktır. Bizim durumumuzda değişken a. Tercüman nesneden alacak Lexicalenvironmentve değişken b. Nesneden pencere.. Tabii ki, eğer yerel bir değişkenimiz varsa b. Bazı değerlerle, nesneye kaydedilecektir. Lexicalenvironment Ve daha sonra oradan ve dış görünürlük alanından değil.

ÖNEMLİ! Bu mülkü hatırla [] Fonksiyonun ilan edildiği ve neden olmadığı bir yer tarafından kurulur, bu nedenle aşağıdaki kodun, bazılarının düşündüğü gibi 3 numarayı 3 ve 5 numarayı görüntüler.

BAR B \u003d 2;
X (a) işlevi (
Uyarı (A + B);
}

Y () işlevi ()
var b \u003d 4;
x (1);
}

Hepsi sadece her şeyin nasıl çalıştığını anlamak için bir prelude oldu ve kapanışların nasıl çalıştığını anlamanız daha kolaydı. Ve şimdi doğrudan makalenin konusuna dönüyoruz.

Dediğim gibi, nesne Lexicalenvironment Her seferinde her seferinde fonksiyonu yürüttükten sonra tahrip edilir ve yeniden arama yapılırken tekrar oluşturulur. Ancak, bu verileri kaydetmek istiyorsak? Şunlar. Her şeyin kaydedilmesini istiyoruz Lexicalenvironment Şimdi, korunmuştur ve aşağıdaki zorluklar için kullanıldı mı? Bunun için kapanma.

Fonksiyon tebrik (isim) (
// lexicalenvironment \u003d (İsim: "nikolai")
Dönüş işlevi () () (// [] \u003d lexicalenvironment
Uyarı (isim);
};
}

Var func \u003d tebrik ("nikolai");
tebrik \u003d null;
Func ();

Bakalım ne yaptığımızı görelim. İlk önce bir işlev yaratıyoruz selamlama.adı hangi adın geçtiği. İşlev bir nesne oluşturur LexicalenvironmentMülkiyetin yaratıldığı yer (yerel değişkenimiz) İsim. Ve "Nikolai" adını atadı. Ve şimdi Önemli: İçinizden çıkardığımız işlevden başka bir işlev dönüyoruz. uyarmak. değişken İsim.. Ayrıca bir değişken atarız func. İşlevten döndürülen değer selamlama.Ve bu değer, bir ad gösteren işlevimizdir. şimdi biz selamlama. Atarız bOŞ. Sadece işlevimizi yok ediyoruz selamlama.Ancak, aradığımız zaman func.O zaman değişkenin değerini göreceğiz İsim.("Nikolai") işlevleri selamlama.. Sizi söylemek nasıl mümkün olabilir? Ve çok basit. Mesele şu ki, iade edilen fonksiyonumuzun bir mülke sahip olmasıdır. [] Hangi dış görünürlük kapsamını ifade eder ve bu bizim durumumuzdaki bu dış kapsam bir nesnedir. Lexicalenvironment Fonksiyonumuz selamlama.. Bu nedenle, işlevimizi sildiğimiz gerçeğine rağmen selamlama., bir obje Lexicalenvironment Silinmemiş ve bellekte kalmamıştır ve en az bir bağlantı olana kadar hafızada kalacaktır. Bu bağlantımız var - değişkeni kullanan iade işlevimiz İsim. bu tesisin Lexicalenvironment.

Yani, şimdi tanımını verelim. kapanış nedir.

Devre - Kullanılabilir tüm değişkenlerle işlev görür.

Peki, makale oldukça hacimli ortaya çıktı, ancak bu sadece kapanma iş sürecini tarif etmeye çalıştığım için. Konsolide etmek için basit bir örnek getirmek istiyorum - sadece okudu konuyu kullanarak bir metre. Lütfen kodla başa çıkın ve yorumlara, nasıl ve neden işe yaradığını yazın. Bir şey anlamıyorsanız, bir soru sorabilirsiniz. Dikkatiniz için teşekkürler!

Fonksiyon makeciounter () () () ()
var chururesCount \u003d 0;

Dönüş işlevi () () ()
CurrentCount ++;
Geri dönüş akımı varsayımı;
};
}

Var sayaç \u003d makeciounter ();
Sayaç ();
Sayaç ();
Alarm (sayaç ()); // 3.

İÇİNDE JavaScript işlevleri Sadece birbiri ardına değil, aynı zamanda diğerinin içinde de tanımlanabilir. Bir işleviniz varsa, diğerinin içinde olduğunda, dahili poacture alternatif bir harici fonksiyona erişebilir.

Harici fonksiyon (x) (x) (var tmp \u003d 3; dahili (Y) (alarm (x + y + (++ tmp)); // 16) Dahili (10);) dış (2);

Bu kod her zaman 16 verir, çünkü iç fonksiyon, funkuction harici bir değişken olan X'i görür. İÇİNDE bu durum Argüman işlevi. Ayrıca dahili (), TMP'yi dışdan () görebilir.

Buna kapatma veya kapatma denir. Daha kesin olarak, kapatma harici fonksiyona denir ve içindeki her şey kapanma ortamı veya kapatma ortamı denir.

Bazen, kapatmanın işlevi döndüren bir fonksiyon olduğu söylenir, yanlış olan, iç fonksiyonun kapsamın dışındaki değişken için geçerli olduğu işlevini adlandırmak için yanlış.

Foo Foo (x) (VAR TMP \u003d 3; İADE FONKSİYONU (Y) (ALER) (Uyarı (X + Y + (++ TMP)); // ayrıca 16))) VAR BAR \u003d FOO (2); // bar şimdi bir kapandı. Bar (10);

Yukarıdaki işlev ayrıca 16'yı gösterecektir, çünkü FOO tamamlandıktan sonra bile çubuk, çubuk değişkeninin kendisi açıklandıkları kapsamın içinde olmasa bile, X ve TMP'ye erişmeye devam eder.

Aynı zamanda, TMP değişkeni hala çubuk kapağının içinde olduğundan, her zaman aramayı artırmaya devam ediyor.

Buraya en basit örnek Devre:

Var a \u003d 10; İşlev testi () () (console.log (a); // Sonuç 10 konsol.log (b); // Sonuç 6) var b \u003d 6; Ölçek ();

JavaScript'te bir fonksiyon başlattığınızda, ortam bunun için yaratılır, yani, bunun için görünen tüm değişkenin bir listesi, sadece bunun içindeki argümanlar ve değişkenler değil, aynı zamanda dışarıda, bu örnekte "a " ve B".

Bir ortamda birden fazla kapatma oluşturabilir, bunları bir diziye, nesneye veya küresel bir değişkene ekleyebilirsiniz. Bu durumda, hepsi çalışırlar aynısı Bireysel kopyalar oluşturmadan X veya TMP değeri.

Örneğimizden beri X, sayı, sonra değeri kopya Foo'da argümanı olarak x.

Öte yandan, JavaScript her zaman nesneler iletildiğinde bağlantıları kullanır. Foo'yu bir nesneyle argüman olarak adlandırdıysanız, geri dönüş kapışı bağlantısını orijinal nesneye geri döndürür!

Foo Foo (x) (VAR TMP \u003d 3; Dönüş Fonksiyonu (Y) (Uyarı (X + Y + TMP); X.MEMB \u003d X.MEMB? X.MEMB + 1: 1; Uyarı (X.MEMB);) ) Var yaş \u003d sayı (2); var çubuğu \u003d foo (yaş); // bar şimdi yaşa atıfta bulunarak bir kapatma. Bar (10);

Beklendiği gibi, her arama çubuğu (10) X.MEMB'yi arttırır. Beklenmeyeceğiniz şey, böylece X, yaş olarak aynı nesneyi ifade etmeye devam eder! İki çağrı çubuğundan sonra, Age.Memb 2'ye eşit olacaktır! Bu arada, HTML nesnelerindeki bellek sızıntıları meydana gelir.

Programlama, kapatma veya "kapatma" ingilizce sürümünde, birinci sınıf fonksiyonlarında bağlamsal bağlama adını uygulamak için bir yöntemdir. Ameliyathane, işlevi ortamla birlikte depolayan bir giriştir. Çevre, her bir serbest fonksiyonun, JavaScript'i kapatarak denilen bir değer veya referansla karşılaştırılmasıdır. Bölge dışında bile olsa bile, değerler veya bağlantıların kopyaları yoluyla yakalanan değişkenlere erişim sağlar.

Kapanış Kavramı

1960'larda, 1960'larda hesaplamadaki ifadelerin mekanik bir değerlendirmesi için geliştirildi ve 1970 yılında, birinci sınıf fonksiyonları desteklemek için birinci sınıf fonksiyonları desteklemek için PAL programlama dilinin bir özelliği olarak uygulandı. Peter Landin, 1964'teki "kapatma" terimini, sözcüksel bir ortamla ilişkili olan Lambda ifadelerini değerlendirmek veya JavaScript'e kapanmasına neden olan Lambda ifadelerini değerlendirmek için SECD makinesinde kullanılan orta ve kontrol kısmı ile tanımladı.

Böyle bir açıklama 1975'te, sözlüksel olarak sınırlı bir LISP versiyonu olarak dahil edildi ve yaygındı. Sözlüksel ortam, programdaki çeşitli geçerli değişkenlerdir. Bir iç sözlük ortamından ve olmayan değişkenler adı verilen harici bir ortama referanslardan oluşur.

JavaScript'teki sözlük kapakları dış ortamıyla özelliklerdir. Javascript'te olduğu gibi, tüm değişkenler türüne bağlantı vardır. JS, yalnızca C ++ 11'e tekabül eden referansla bağlanma kullanır ve fonksiyon tarafından yakalanan yerel olmayan değişkenlerin ömrü fonksiyonun ömrü boyunca dağıtılır.

JavaScript'teki devreler genellikle birinci sınıf değerlere sahip dillerde görünür. Bu tür diller, fonksiyonları argümanlar olarak iletmenize izin verir. Ayrıca özellik aramalarından geri dönün ve değişken adlarına ekleyin. Bu, dizeler ve tamsayılar gibi basit tipler gibi olur.

Bu örnekte, Lambda ekspresyonu (Lambda (\u003e \u003d (kitap satış kitabı) eşiği) en çok satan kitap fonksiyonunda görünür. Lambda ekspresyonu hesaplandığında, devre, lambda ekspresyonu için koddan oluşan bir kapatma ve lambda ifadesinde serbest bir değişken olan eşik değişkenine referans oluşturur. Kapanış daha sonra, hangi kitapların sonuç listesine hangi kitapların eklenmesi gerektiğini ve atılmaları gerektiğini belirleyen filtre işlevi ile iletilir.

Eşiğin değerinde bir kapanma olduğundan, ikincisi filtre nedeni her zaman kullanabilir. Filtre işlevinin kendisi mükemmel şekilde tanımlanabilir ayrı dosya. İşte JS'de yeniden yazılan aynı örnek. JavaScript çalışmalarında kaputun altındaki kapakların nasıl olduğunu gösterir.

Buradaki anahtar kelime, genel filtre işlevi yerine kullanılır, ancak yapının geri kalanı ve kodun etkisi aynıdır. İşlev daha yakın oluşturabilir ve geri döndürebilir, çünkü bu durumda, Fonksiyonun F ve DX'in türevinden sonra çalışmaya devam edilmesine devam edilmesine devam edilmesi durumunda, bu durumda, yürütme kapsamını bıraksa bile, türevden sonra çalışmaya devam ederken ve bunlar görünmüyorlar.

Dillerde, kapanmadan, otomatik yerel değişkenin ömrü, bu değişkenin ilan edildiği yığın çerçevesinin yürütülmesiyle çakışıyor. Javascript'teki dillerde, IFE'nin kapanması ve işlevleri, mevcut kilitlerin kendilerine referanslı olana kadar değişkenler devam etmelidir. Bu genellikle bir miktar çöp toplama şekli kullanılarak uygulanır.

Kapanmanın avantajı, kapsamın, "görünürlük zincirini" bir dış veya "ebeveynlik zinciri" bir yürütme bağlamını tutmasıdır. Bu tür davranış çeşitli şekillerde kullanılabilir ve çeşitli javascript hatalarını önlemek için yararlı bir araç haline gelmiştir. En yaygın olanlardan biri "döngüler" sorunudur.

Döngüyle ilgili sorun, kullanıcı döngüde bir işlev oluşturduğunda ve bu değişkenin geçerli değerini beklerken oluşur. yeni fonksiyonYeni bir işlevi çağırmadan önce döngü bağlamında değişse bile. Bu şekilde kullanılan kapaklar artık referans şeffaflığına sahip değildir ve bu nedenle artık temiz işlevler değildir, ancak genellikle şema gibi kirli fonksiyonel dillerde kullanılırlar. Javascript'te neyin kapandığını anlamak için, kullanım vakalarını düşünmeniz gerekir. Aslında, pratikte birçok uygulamaları var:

  1. Kontrol yapılarını belirlemek için kullanılabilirler. Örneğin, dallar (eğer / daha sonra / diğerleri) ve döngüleri (iken ve için) dahil olmak üzere tüm standart SmallTalk yönetim yapıları, yöntemleri kapanan nesneler kullanılarak belirlenir. Kullanıcılar kontrol yapısını belirlemek için kolayca kapanışları da kullanabilir. Amaç uygulayan dillerde, çok işlevli ortamı oluşturabilir, bu ortamı gizli iletişim kurmanıza ve değiştirmenize izin verebilirsiniz. Kapatma, nesne sistemlerini uygulamak için kullanılır.
  2. Modül şablonlarını kullanarak hem özel hem de halka açık değişken yöntemleri oluşturma. İade edilen özelliklerin ana fonksiyonun alanını devralmasından dolayı, bu bağlamdaki tüm değişkenler ve argümanlar için mevcuttur.
  3. İşlevin her arama için aynı kaynağı kullandığı bir durumda faydalıdır, ancak bunun için bir kaynak oluşturur. Bu durum, yöntemi etkisiz hale getirir, bu da sadece kapanarak ortadan kaldırılır.

MDN'ye (Mozilla Geliştirici Ağı) 'ye göre "kapaklar, yaratılmasının ortamını" hatırlatan bağımsız değişkenlerle işlev görür. " Ve bir kural olarak, işlev tamamlandığında, yerel değişkenleri artık mevcut değil. JavaScript'teki kapanmanın nasıl çalıştığını anlayın, birkaç mekanizmayı düşünebilirsiniz. Birincisi resmi bir mantıktır. Örneğin, bir ad parametresi olarak bir isim alan ve kaydedecilen logname işlevini uygulayarak. Sonra, döngülerin isim listesinden geçmesi için, 1. zaman aşımını ayarlayın ve ardından geçerli adda geçen LOGNAME işlevini arayın.

Birinci sınıf dilde, INT veya Dize gibi diğer verilerle aynı şekilde manipüle edebilirsiniz. Yalnızca bu mekanizma, çoğu, örneğin, daha sonra aramaya veya başka bir fonksiyonun bir parametresi olarak iletirken bir değişken işlevi atamak için inanılmaz şeyler yaratmasını sağlar.

Bu ilke birçok yapı tarafından ve DOM etkinlik işleyicileri tarafından kullanılır. İlk olarak, olay "dinliyor", ardından olay tetiklendiğinde aranacak bir geri arama işlevi atayın.

Anonim işlev, adı olmayan bir işlevdir. Neredeyse acemi programcılar, oyunları sayılarla anlamadan günlük olarak buluşur. Örneğin, ekleme işleminin gerçekleştirilmesi, örneğin değişkenlerden geçebilirsiniz:

  • var x \u003d 3;
  • y \u003d 5;
  • var z \u003d x + y.

Ya da numaraları yeniden işleme niyetinde değilseniz: var z \u003d 3 + 5;

Bunlar isimsiz odalar. Anonim fonksiyonlar için, değişkeni geçmeden "sinek üzerinde" kullanıldığında bunları ilan edebilirsiniz. Örneğin, işlevi daha önce yapınız:

(Alert ("Ceci Est Fonchan Anonyme");

Ayrıca, her iki fonksiyonun da anonim olabileceğini vurgulayan ve geri arama işlevini yüklemenin uygun bir yolu olan basit değişkenlere başvuran bir fonksiyonun bildiriminin alternatif bir sözdizimi vardır.

Aslında, aynı mekanizma, ancak bu açıdan, işlevin içeriden nasıl kapandığını görmenizi sağlar. Görülebileceği gibi, işlevler değişken olduğundan, diğerleri gibi, yerel olarak tanımlanamadıkları bir sebep yoktur. C, C ++ ve Java gibi sıfır sırayla, tüm fonksiyonlar aynı sınıfta veya küresel düzeyde bir görünürlük seviyesinde belirlenir. Öte yandan, JavaScript'te, yerel fonksiyon, yanı sıra, diğer yerel değişkenlerin yanı sıra, ana işlev bitmez diğer işlevlerden görülmez.

Bu aslında zordur, ancak JavaScript, değişkenlerin görünürlüğünü ve hatta iki şekilde izlemenin bir yolunu vardır. JavaScript'te bir küresel değişken atama, Java - karmaşık nesnelerde olduğu gibi aynı mekanizmaya, diziler, DOM elemanları ve diğerleri referans olarak iletilir, bu nedenle aşağıdaki kodda:

var sekmesi \u003d; Var Tab2 \u003d sekmesi.

Nerede, sekme ve Tab2 aynı tabloya iki bağlantıdır, teknik olarak bunlar çöp toplayıcısı tarafından kontrol edilen göstergelerdir. İşlevler ayrıca referans olarak iletilir. GlobalFN değişkeni artık gizlenmiyor. Sipariş, JavaScript kapatma görevi örneğinde gösterilenleri yapmanızı sağlar.

İşlev diğer yerel değişkenleri yerine getirirse, işlevi yerel bağlamdan nasıl ayıklayabileceğinizdir. Basit bir örnek: Otomatik artış, her seferinde 1 artan bir tamsayı döndüren bir işlev. Özellikle, INC işlevi ihtiyaçları gibi davranan:

// retourne 0 inc ();

// retourne 1 inc ();

// retourne 2 inc ();

Kapanışla şöyle görünüyor:

fonksiyon makeinc () () (var x \u003d 0; dönüş fonksiyonu () (döndürme x ++;)) var inc \u003d makeinc ();

Son sırada şu anda Inc değişkeninin oluşturulduğu durumlarda, bu durumda bu durumda bazı değişkenleri taşır. Bu değişkeni içeren fonksiyonun etrafında belirli bir görünmez nesne oluşturur. Bu nesne bir JavaScript kapatma işlevidir. Aynı zamanda, fonksiyonun her bir kopyası kendi kapanması olacaktır:

var inc1 \u003d makeinc ();

var inc2 \u003d makeinc ();

Görüldüğü gibi, kapanma birçok durumda çok faydalıdır.

Değişken isim çakışmalarını önlemek için, ad alanı genellikle kullanılır. Javascript'te, ad alanları diğerleri gibi nesnelerdir.

Naturally, A.x ve B.x aynı değişken değildir. Bununla birlikte, eğer sadece komut dosyasını başlatmanız gerekirse, gerisi için değişkenleri kaydetmeden, anonim bir işlev bir kapatma olarak kullanılabilir. Bu biraz garip bir sözdizimi verir. Ortadaki iki kod oldukça yaygın olsa da, diğer yandan, etrafta bulunan işlev "sinek üzerine" yapılır. Sonunda parantezlere () dikkat edin. Ve bir kapatma yapabilmek, anonim fonksiyon Kendisi yuvarlak parantezlerle çevrili olmalıdır.

Bu anonim fonksiyonda yerel bir değişken, paragraf kullanın. Bu, isim çatışmalarını veya sıyrılmayı önlemek için harika bir yoldur, aynı zamanda ataks xss. Özel değişkenler korunur, hiç kimse betiğin davranışını etkilemek için bunları değiştiremez.

Bir seçenek var: (işlev () (// ...) ());

Aynı zamanda parantezlerin permütasyonuna dikkat çekmek. Bu iki seçeneğin arasındaki fark açıklaması oldukça zordur, çünkü kodun sözcüksel bir analizör tarafından nasıl okunduğu ile ilişkilendirilirler. Her iki durumda da, işlev bir ifade olarak kabul edilir, ancak bu ifade aynı anda tahmin edilmez. Sadece iki çift yuvarlak parantez alacağını hatırlamanız gerekir: biri fonksiyonun etrafında ve arkasında.

Döngülerde JavaScript programlama

Kullanıcı büyük miktarda JavaScript programlama gerçekleştirdiğinde, döngüleri önlemek zordur. Birisi çılgınca, ardından JavaScript'in herhangi bir uygulamasının ciddi bir hatası olduğu fikrine geliyorlar. Geliştiricinin, iTeratörün işlevini kullanmaya dönüştürmek istemiyorsa, yapması gereken her şey, yeni değişkenleri tanımladığı bir kapanıştır. Değişkenlerin mevcut değerini düzeltirler ve her bir yinelemede değişmektedir. Değişkenleri yakalamanın numarası, dış kapamanın, döngünün mevcut yinelemesi sırasında derhal yapıldığıdır. Bu iki yaklaşık yaklaşımdan birini kullanabilirsiniz.

Şimdi bu soruna basitleştirilmiş bir çözüm var, çünkü anahtar kelime hem Firefox'ta hem de Chrome'da destekleniyor. Bu anahtar kelime Var değişken bloğu yerine. Sihirli bir şekilde çalışmasına izin verin, çünkü yeni bir değişken J bildirildiği, değerinin döngünün içindeki kapakla sabitlendiği değeridir. Bununla birlikte, yerel olarak olduğundan, döngünün aynı yinelemesinin sona ermesinden sonra var olmaya devam etmediğini akılda tutulmalıdır.

Döngü ve fonksiyon

JavaScript'te bir döngü için, C veya Java'daki bir döngü için görünmüyor. Aslında, php gibi görünüyor. JS'deki devirlerle ilgili en önemli bilgi, bir eylem alanı oluşturmadıklarıdır. JS bir küre bloğu yok, sadece birimin işlevi. Bu özellik aşağıdaki fragman üzerinde düşünülebilir:

foo Foo () () (var çubuğu \u003d 1;

için (var i \u003d 0; ben< 42; i++) {var baz = i;} /* more code */}

Bu çubuğun tüm fonksiyonda mevcut olduğu açıktır. BAZ döngüsünün ilk yinelemesinden önce tanımlanamaz. Döngünüzden sonra, 41 değeri olacaktır (ve ben 42 olacağım). Böylece, fonksiyonun herhangi bir yerinde bildirilen herhangi bir değişken, fonksiyonun her yerinde mevcut olacak ve yalnızca ona atandıktan sonra geçerli olacaktır.

Kepenkler ve Toplama

Kapatma, diğer fonksiyonların içindeki işlevlerden daha fazla bir şey değildir ve diğer bazı bağlamlara iletilir. Yerel değişkenler aracılığıyla kapanır, yani, kürenin diğer bölgelerine erişilebilir. Örneğin, X, Foo parametresi olarak tanımlanan ve VAR BAR \u003d FOO (2) () dönemi 84 döndürür.

İade Edilen Foo Fonksiyonu X'e erişebilir. Bunların hepsi önemlidir, çünkü geliştiricilerin döngü değişkenlerine bağlı olarak çevrim içi işlevler oluşturmalarına yardımcı olur. Çeşitli öğelere tıklama işlemcisini atayan bu parçayı düşünün:

// elements, 3 DOM elemanının bir dizisidir var VAR değerleri \u003d ["foo", "bar", "BAZ"];

bEN.< l; i++) {var data = values[i];

elements [i] .onclick \u003d fonksiyon () (alarm (veriler);

Basıldığında uyarı kullanacakları değer, Herkes için aynı olacak, yani Baz. O zamana kadar, olay işleyicisi zaten tamamlandı. JS bir blok alanı yok, yani. Tüm işleyiciler bağlantıyı aynı veri değişkenine kullanır. Döngüden sonra, bu değer değerler olacaktır. Her değişken bildirimi, depolama hafızasında bir yer oluşturur. İçin, bu veriler tekrar tekrar değiştirilir ve bellekteki konum değişmeden kalır.

Her olay işleyicisi hafızadaki aynı konuma erişebilir. Tek çözüm, mevcut veri değerini "düzelttiği" başka bir alana girmektir. JS'nin sadece bir dizi işlevi var. Bu nedenle, başka bir işlev girilir. Misal:

fonksiyon CreateEveVentHandler (x) (Dönüş işlevi () () (Alert (x);

için (var i \u003d 0, l \u003d Elements.Length;

bEN.< l; i++) {var data = values[i];

elements [i] .onclick \u003d CreateEventHandler (veri);

Çalışır, çünkü veri değeri yerel alanda saklanacak, CreateEventHandler ve bu işlev her bir yinelemede gerçekleştirilir. Yürütülebilir işlevleri derhal kullanarak kısa yazılı olabilir:

için (var i \u003d 0, l \u003d Elements.Length;

bEN.< l; i++) {var data = values[i];

elementler [i] .onclick \u003d (işlev (x) (işlev () () (Uyarı (x);

JavaScript'te pratik kapanma örneği

Kullanıcı tarayıcıdaki kodun hemen üstünde kapanıyorsa, herhangi bir sözdizimi hatası yapabileceği için bir sorunla karşılaşabilir. Kodu doğrudan tarayıcıda yürütürse, web paketi derleme işlemini derlememek için şanslar çok yüksektir. Muhtemel çözümler:

İşlev Çalışması (Ad) (

İade işlevi (konu) (

console.log ($ (name)) cinsinden ($ $ (konu));

İş ("javascript") ("kapatma");

İlk olarak, işlev çağrılır ve adı argümanı iletilir. Şimdi bu kelime fonksiyonu da konu tartışmalarını kabul eden bir işlev döndürür. Bu özellik çıkışı kaydeder ve çıkış değişkene erişebilir.

Insider fonksiyonları alanı bu fonksiyonla sınırlı değildir, bu nedenle konseptin bu alana erişimi olduğu için kapanma denir. harici parametre. İade edilen fonksiyon, harici sözcük bölgesine veya bağlamlara erişebilir. Geliştirici, geri döndüren bir işlevi çağırdığında, ilk olarak denir değişken fonksiyonu Dahili işlev için her zaman kullanılabilir. Aşağıdaki kodla daha fazla örnek.

Dahili bir fonksiyon örneği

JavaScript'teki kapatma hakkında daha fazla bilgi edinin, ikinci örnekte söylenebilir. Şimdi bu Yerine Getiren ortam yok edildi, ancak parametrenin adı hala var. Anonim bir işlev olan yeni bir dahili fonksiyonel ortam oluşturulur. Dış sözcük ortamının alanına erişebilir.

Böylece, dış ortamın değişkeninde, hala anonim bir işlevin, örneğin "JavaScript'teki bir kapanma nedir" olarak ad değişkeni yazdırmalarına erişebilmesi böyle bir şekilde vardır. Dahili anonim fonksiyon //main.js

function Fabrika () () (var ürünler \u003d;

i ++) (Ürünler.Push (Function () (Console.log (i);

) İade Ürünleri;

) Var sabun \u003d fabrika ();

Bu örneğin sonucu oldukça önemsizdir ve 2'ye eşittir.

SOAP sabun olduğunda () harici bir içerik değişkeni olarak adlandırıldığında, her zaman 2, çünkü durumdaki durum yanlıştır.<2, поэтому при этом значение i равно 2, а во время вызова нужно напечатать значение в консоль так, она всегда пишет 2. То же самое для мыла - soap ().

"Anında" işlevleri oluşturma

Bir fonksiyon fabrikası oluşturabilirsiniz - Özel görevleri uygulayan fonksiyon factorfictory. İşlev fabrikasından elde edilen fonksiyon, bir kapatma, oluşturma depolama ortamı olacaktır.

var fonksiyonufactory \u003d fonksiyon (num1) (Dönüş num1 * num2;

Yukarıdaki, bir işlev fabrikası numarasını aktarmanızı sağlar. Sonra İşlev Fabrikası, Num1 değerini hatırlayan bir kapatma döndürür. Elde edilen fonksiyon, orijinal Num1 katını, adlandırıldığında iletilen Num2'nin değerini çarpar.

var Mult5 \u003d FunctionFactory (5);

var Mult10 \u003d FunctionFactory (10);

Yukarıdakiler basitçe Mult5 ve Mult10 işlevini oluşturur. Artık 5 veya 10'a kadar çarpmak için yeni bir numarayı geçerek bu işlevlerden herhangi birine başvurabilirsiniz. Şimdi sonucu görebilirsiniz.

Kapatma, en güçlü JavaScript işlevlerinden biridir, ancak özü anlamadan doğru kullanılamaz. Onlar nispeten yaratılması kolaydır, bu ne kadar tehlikeli kapanışları JavaScript. Yaratılışları, özellikle nispeten ortak web tarayıcı ortamlarında potansiyel olarak zararlı etkilere sahiptir. Dezavantajları ile rastgele çarpışma önlemek ve sundukları avantajlardan yararlanmak için, mekanizmalarını anlamak gerekir.

Bu yazıda, birçok deneyim yaşadığı JavaScript'te görünürlük ve kapanma alanlarını açıklamaya çalışacağım.

Giriş

Ağda görünürlük ve kapatma alanlarını açıklamaya çalışan çok az sayıda makale var, ancak genel olarak, çoğunun çoğunun tamamen anlaşılmaz olmadığını söyleyebilirim. Buna ek olarak, bazı makalelerde, 15 dilden önce programlandığınız varsayılmaktadır, ancak JavaScript'te yazılan kişilerin çoğunun yalnızca HTML ve CSS'de deneyimi yaşadığı ve C veya Java'da deneyimliliği olduğunu düşünüyorum.

Sonuç olarak, bu makalenin amacı hepsini açıklamaktır - görünürlük ve kapatmanın kapsamı nedir, çalıştıkları gibi ve en önemlisi ne kadar avantajlarıdır. Bu makaleyi okumadan önce, JavaScript'teki değişkenler ve işlevler hakkındaki temel kavramları bilmeniz gerekir.

Görünürlük alanı

Kapsam, değişkenlerin ve fonksiyonların mevcut olduğu ve hangi bağlamda yürütüldüğü anlamına gelir. Bir değişken veya fonksiyon, küresel veya yerel bir görünürlük alanında tanımlanabilir. Değişkenler, işlev görünürlüğünün sözde fonksiyonuna sahiptir ve fonksiyonlar değişkenlerle aynı kapsama sahiptir.

Küresel kapsam

Bir şey küresel olduğunda, kodunuzdaki herhangi bir yerden mevcut olduğu anlamına gelir. Bir örnek düşünün:

var maymun \u003d "goril"; Fonksiyon Greettisitor () (Dönüş Uyarısı ("Merhaba Sevgili Blog Okuyucu!");)

Bu kod bir Web tarayıcısında gerçekleştirildiyse, görünürlük alanı penceresi olursa, pencerede yürütülen her şey için uygun olacaktır.

Yerel kapsam

Küresel görünürlük alanının aksine, yerel görünürlük alanı bir şeyin tanımlandığı ve yalnızca bir fonksiyon gibi kodun bir kısmında kullanılabilir olduğunda. Bir örnek düşünün:

fonksiyon TalkDirty () (var diyor \u003d "Oh, seni küçük vb sevgilisi, sen"; dönüş uyarısı (söyleyerek);) Uyarı (söyleyerek); // bir hata attı

Bu örnekte, değişken, yalnızca tanımlanmadığı dışında, yalnızca TalkDirty işlevinin içinde bulunur. Not: Bir var anahtar sözcüğü olmadan söyleyerek tanımlanmışsanız, otomatik olarak küresel olur.

Ek olarak, iç içe geçmiş fonksiyonlarınız varsa, dahili fonksiyonun gömülü olan işlevlere, ayrıca değişkenlere erişebileceği:

function CapitalizEname (FirstName.Tuppercase ());) Var Cinsitized \u003d CapitalizEname (); Dönüş büyük harf;) Uyarı (Savename ("Robert")); // "Robert" döndürür

Az önce gördüğünüz gibi, Dahili İşlev CapitalizEnamenin herhangi bir parametreyi iletmemesi gerekmez, çünkü SaveNamenin harici işlevindeki ad parametresine tam erişime sahiptir. Daha fazla netlik için, başka bir örneği göz önünde bulundurun:

fonksiyon kardeşleri () () (varlıklar \u003d "," John "," Liza "," Peter "]; fonksiyonu SiblingCount () () (varlıklar grubu \u003d kardeşler. Uzun boylu; geri dönüş kardeşleri uzunluğu;) fonksiyonu joinsiblingnames () (iade" i 'i "+ SiblingCount () + "Kardeşler: nn" + siblings.join ("n");) JoinSiblingnames ();) uyarısı (kardeşler ()); // çıktılar "3 kardeşim var: John Liza Peter"

Gördüğünüz gibi, her iki iç işlev de kardeş dizilerine erişebilir ve her bir dahili fonksiyonun aynı seviyedeki başka bir dahili fonksiyona erişimi vardır (bu durumda, JoinSiblingnames'in SiblingCount'a erişimi vardır). Bununla birlikte, SiblingCount içindeki SiblingsLength değişkeni yalnızca bu fonksiyonun içinde mevcuttur, yani. Bu görünürlük alanında.

Devre

Şimdi görünürlük alanı hakkında daha net bir fikriniz var, onlara kapanma ekleyeceğiz. Devreler ifadelerdir, genellikle belirli bir bağlamda bir dizi değişkenle çalışabilen işlevlerdir. Veya daha basit kelimeler, dış fonksiyonların yerel değişkenlerine başvuran dahili işlevler kapanıyor. Örneğin:

fonksiyon ekle (x) (x + y döndürür;);) var add5 \u003d eklemek (5); var no8 \u003d add5 (3); Uyarı (NO8); // 8 döndürür.

Blimey! Burada neler oluyor? Hadi anlayalım:

1. Ekle işlevini aradığımızda, işlevi döndürür.

2. Bu fonksiyon bağlamı kapatır ve X parametresinin şu anda nasıl olduğunu unutur (yani, bu durumda, 5 değeri)

3. Ekleme işlevinin sonucu ADD5 değişkenine atandığında, bu değişkeni oluştururken neyin olduğunu daima bilecektir.

4. Add5 Değişkenliği, her zaman 5 değeri 5 katkı maddesi ekleyecek bir işlevi belirtir.

5. Bu, ADD5 değerini 3 ile aradığımızda, 5 ve 3 numarayı katlayacağını ve 8'i geri döndüreceği anlamına gelir.

Aslında, JavaScript dünyasında, ADD5 işlevi şöyle görünür:

fonksiyon ekle5 (y) (geri dönüş 5 + y;)

Bodrumun ünlü sorunu
Kaç kez, örneğin bir öğeyi, örneğin bir öğeyi, bir öğeyi, bir öğeyi, bir öğeyi, yalnızca iade ettiğimin yalnızca son değerin olduğunu anladınız mı?

Yanlıştemyiz

5 element oluşturan bu hatalı koda bakalım , i değerini, her bir öğeye metin olarak ekler ve bu referans için I değerinde uyarı üretmesi beklenen, yani, yani, I.E. Öğenin metninde olduğu gibi aynı değer. Ardından, elemanlar belge gövdesine eklenir:

<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); }; document.body.appendChild(link); } } window.onload = addLinks;

Her bir eleman doğru metni içerir, yani. "Link 0", "Link 1", vb. Ancak tıkladığınız bağlantı ne olursa olsun, bir numara ile uyarı gösterir. Sorun nedir? Bunun nedeni, değişkenin değerinin, döngünün her bir yinelemesiyle 1'i artırdığıdır ve çünkü OnClick olay yerine getirilmez, ancak sadece eleman için geçerlidir. Değer artar.

Bu nedenle, döngü, 5'e eşit olana kadar çalışmaya devam eder, bu da AddLinks işlevinden çıkmadan önce son değerdir. Ayrıca, OnClick olayı her tetiklendiğinde, son değeri alındığında.

Uygun temyiz

Yapmanız gerekenler bir kapanma oluşturmaktır. Sonuç olarak, I değerini bir OnClick olay olayına uyguladığınızda , Ben o dönemde i değerini atayacağım. Örneğin, şöyle:

İşlev addlinks () (için (var i \u003d 0, link; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function (num) { return function () { alert(num); }; }(i); document.body.appendChild(link); } } window.onload = addLinks;

Bu kodu kullanarak, ilk öğeye tıklarsanız, uyarısı "0", ikincisinde "1", vb. Solüsyon, OnClick olayına uygulanan dahili fonksiyonun, Num parametresinin temyiz edildiği bir kapak oluşturduğu, yani. O zamanda I'in değerine.

Bu özellik "istenen değeri" hatırlar ve ONClick olayı tetiklendiğinde karşılık gelen rakamı döndürür.

Güvenli Yürütme İşlevleri

Güvenli yürütme işlevleri, derhal yürütmeye başlayan ve kapanışlarını yaratmaya başlayan bu tür fonksiyonlardır. Bir örnek düşünün:

(Fonksiyon () (var dog \u003d "Alman çoban"; alarm (köpek);)) (); Uyarı (köpek); // tanımsız döndürür.

Böylece, köpek değişkeni yalnızca bu bağlamda mevcuttur. Düşünce, Gizli Değişken Köpek ... Ama arkadaşlarım, en ilginç şey bununla başlar! Sorunumuzu bir döngü ile çözdü ve aynı zamanda Yahoo JavaScript modül deseni için de temel.

Yahoo javascript modül deseni

Bu kalıbın özü, bir kapatma oluşturmak için güvenli bir şekilde yürütülebilir bir işlev kullanmasıdır, bu nedenle özel ve genel özellikleri ve yöntemleri kullanmayı mümkün kılar. Basit Örnek:

var kişi \u003d fonksiyon () () () (// private var name \u003d "robert"; geri dönüş (GetName: Function () (dönüş adı), SETNAME: fonksiyon (yeni isim) (ad \u003d yeni adı;));) (); uyarısı (kişi.Name); // undefined alert (kişi.getname ()); // "Robert" Person.setName ("Robert Nyman"); alarm (kişi.getName ()); // "Robert Nyman"

Bu yaklaşımın avantajı, nesnenizde (ve değiştirilebilen) açılacak olan ve bu kiminle iletişim kuramayacağı veya değişemediği, kendinizi tanımlayabilmenizdir. Ad değişkeni, fonksiyonun bağlamının dışına gizlenir, ancak GetName ve SetName işlevlerine erişilebilir, çünkü Ad değişkenine bir link olduğu kapaklar oluştururlar.

Sonuç

İçtenlikle bu makaleyi okuduktan sonra, yeni gelenler ve deneyimli programcılar, JavaScript çalışma alanlarında görünürlük ve kapanma alanlarında nazik bir fikir aldıklarını umuyorum. Sorular ve yorumlar açığız ve bir şeye izin vermek için önemli bir şeyiniz varsa, makaleyi güncelleyebilirim.

İyi kodlama!

Javascript'teki devreler. Değişken değerleri ve mağaza işlevlerini gizlemek için kullanılır. Mesele şu ki, kapalıyken, değişkenlerin belirtildiği ve bunun bir sonucu olarak çalışmasının bir sonucu olarak iç içe geçmiş işlevi döndürdüğü bir fonksiyon oluşturulmasıdır. Daha sonra, içinde (ana fonksiyonda), bazı işlemlerin değişken fonksiyon değişkenleriyle yapıldığı ve bu işlemlerin sonucunu döndüren bir gömülü fonksiyon oluşturulur. Daha sonra, ana fonksiyon bir değişkene eşittir - bu değişken ne kadar zaman olarak adlandırılabilir ve bununla birlikte, ana fonksiyonun değişkenlerinin değerleri depolanır ve güncellenecektir. O "kapalı".

Bildiğiniz gibi, Javascript'te yerel değişkenlerin görünürlük alanı (Vardı var kelime) Tanımlandıkları fonksiyonun gövdesidir.

Başka bir işlev içindeki bir işlevi beyan ederseniz, ilk, ikincisinin değişkenlerine ve argümanlarına erişir:

Kod: fonksiyonu dışfn (myarg) (
Var myvar;
İşlev InnerFN () (
// Myvar ve Myarg'a erişebilir
}
}

Aynı zamanda, bu tür değişkenler, tanımlandıkları harici fonksiyonun yerine getirildikten sonra bile mevcut olan iç fonksiyon mevcut olmaya devam eder.

Bir örnek düşünün - özdeğer sayısını döndüren bir fonksiyon:

Kod: Function CreateCounter () () () (
var numberofcalls \u003d 0;
Dönüş işlevi () () ()
Geri dönüş ++ numberofcalls;
}
}
var fn \u003d createcounter ();
fn (); //bir
fn (); // 2.
fn (); // 3.

Bu örnekte, Yaratecounter tarafından döndürülen fonksiyon, aramaları arasında istenen değeri kaydeden NumberOFCALLS değişkenini kullanır.

JavaScript'teki bu tür "iç içe geçmiş" fonksiyonların kapaklar (işlevsel dillerden gelen terim) olarak adlandırılması için bu özellikler içindir - bunlar içindeki fonksiyonun değişkenlerini ve argümanlarını "yaklaştırır".

Kapanma Uygulaması

Yukarıda küçük bir örneği basitleştirir - Yaratecounter işlevini ayrı ayrı çağırma ihtiyacını kaldırın, onu ekstrik hale getirin ve reklamından hemen sonra çağırın:

Kod: var fn \u003d (işlev () (
var numberofcalls \u003d 0;
Dönüş işlevi () () ()
Geri dönüş ++ numberofcalls;
}
})();

Böyle bir tasarım, zorlukları arasında kalan fonksiyona veri bağlamamızı sağladı, bu da zorluklar arasında kalan kapakların kullanımlarından biridir. Başka bir deyişle, onların yardımı ile değişken durumuna sahip olan işlevler oluşturabiliriz.

Diğer iyi kapanışların kullanımı - fonksiyonların oluşturulması, sırayla, ayrıca işlevler oluşturur - bazılarının T.N. Metaprogramlama.
Örneğin:

Kod: var createhelloFunction \u003d İşlev (ad) (
Dönüş işlevi () () ()
Uyarısı ("merhaba" + isim);
}
}
var Sayhellohabrahabr \u003d createhelloFunction ("habrahabr");
sayhellohabrahabr (); // "Merhaba, Habrahabr" uyarıları

Kapanış sayesinde, iade edilen işlev "hatırlar", bu tür şeyler için ihtiyacımız olan parametreleri yaratma işlevlerine aktarılan parametreler.

Benzer bir durum, bir dahili işlevi iade etmediğimizde ve herhangi bir etkinliğe asıldığımızda meydana gelir - çünkü olay fonksiyonun yerine getirildikten sonra ortaya çıktığından, kapatma, veri işlemcisi oluşturulduğunda iletilen verileri kaybetmemesine yardımcı olur.

Biraz daha karmaşık bir örnek düşünün - işlevi belirli bir bağlamda bağlayan bir yöntem (yani, bu kelimenin bu konuda belirteceği nesneyi).

Kod: function.prototype.bind \u003d fonksiyon (içerik) (
var fn \u003d bu;
Dönüş işlevi () () ()
Fn.Apply (bağlam, argümanlar) döndürün;
};
}
var hellopage \u003d (
Adı: "habrahabr",
init: işlev () () () ()
Alert ("Merhaba," + this.Name);
}
}
//Window.onload \u003d Hellopage.init; // Alertnul undefined, çünkü Bu pencereyi gösterir
window.onload \u003d hellopage.init.bind (Hellopage); // şimdi her şey çalışıyor

Bu örnekte, bir kapatmanın yardımı ile, bir fonksiyon, tetiklenen bir bağlama "OHM, başlangıç \u200b\u200bişlevini ve kendisine atanan bağlamı hatırlar.

Sonraki, temelde farklı kapakların kullanımı - veri koruma (kapsülleme). Aşağıdaki tasarımı düşünün:

Kod: (işlev () (

})();

Açıkçası, kapanışın içinde tüm harici verilere erişimimiz var, ancak kendine aittir. Bundan dolayı, yerel değişkenleri dışarıda erişimden kapatmak için bir tasarım gibi kodun bir kısmını kuşatabiliriz. (Değişkenleri yalnızca ona vermemek için, tüm kodunun kapanmasını çevreleyen jQuery kütüphanesinin kaynak kodunda bir örnek görülebilir).

Bununla birlikte, böyle bir kullanım tuzağı ile ilişkili bir tane var - bu kelimenin anlamı kapanma içinde kaybolur. Aşağıdaki gibi çözüldü:

Kod: (işlev () (
// en yüksek bu devam edecek
)). (BU) ARAMA (BU);

Aynı serideki başka bir resepsiyonu düşünün. Yahoo UI Çerçevesinin geliştiricileri tarafından yaygın olarak popülerdi, onu "modül deseni" olarak adlandırdı ve resmi bir blogda bir makale yazıyordu.
Herhangi bir yöntem ve özellik içeren bir nesneye (singleton) yapalım:

Kod: var mymodule \u003d (
Adı: "habrahabr",
Saypreved: İşlev (isim) (
Uyarı ("öngörülen" + isim.ToupperCase ())
},
this.saypreved (this.Name);
}
}
Mymodule.sayprevedtoHabrahabr ();

Kapanış yardımıyla, nesnenin dışında kullanılmayan yöntemleri ve özellikleri yapabiliriz. (yani sadece onun için kullanılabilir):

Kod: var mymodule \u003d (işlev () (
Var name \u003d "habrahabr";
İşlev Saypreved () () () ()
Alarm ("öngörülen" + isim.ToupperCase ());
}
Dönüş (
SayprevedtoHabrahabr: İşlev () () () ()
Saypreved (isim);
}
}
})();
Mymodule.sayprevedtoHabrahabr (); // uyarıları "engelli habrahabr"

Son olarak, birçok kişinin nasıl kapatılmasının cehaletinde bir kadına sürdüğü ortak bir hatayı tanımlamak istiyorum.

Bir dizi bağlantımıza sahip olalım ve görevimiz bunu yapmak, her bir alıcıya tıkladığınızda, sıra numarası görüntülenir.
Aklıma gelen ilk karar şöyle görünür:

Kod: için (var i \u003d 0; i< links.length; i++) {
Uyarı (I);
}
}

Aslında, herhangi bir bağlantıya tıkladığınızda, aynı numara görüntülendiğinde - Links.Length'un değeri. Bu neden oluyor? Kapanışla bağlantılı olarak, açıklanan yardımcı değişken, bağlantıya tıkladığımız anda ve şu anda var olmaya devam ediyor. O zamandan beri döngü zaten geçti, ben bağlantı sayısına eşit kalır - bu değer lütfen tıkladığımız değer.

Bu sorun şu şekilde çözüldü:

Kod: için (var i \u003d 0; i< links.length; i++) {
(İşlev (i) (
Linkler [i] .onclick \u003d fonksiyon () () () () ()
Uyarı (I);
}
)) (ben);
}

Burada, başka bir kapanma yardımı ile, her döngü adımında yerel görünürlük alanında bir kopyasını "gölgeleyin" değişkenini "gölgeliyoruz. Bunun sayesinde her şey şimdi tasarlandığı gibi çalışıyor.

Bu kadar. Tabii ki bu makale, ayrıntılı olduğunu iddia etmiyor, ancak birileri, umarım, hala çözmeye yardımcı olur.

zy.
Aramalar arasında kaydetmek için func_name.attr türünü kullanmak daha kolay:

Kod: İşlev Commy (Sıfırla) (
if (reset ||! countiT.cnt) countid.cnt \u003d 0;
geri dönüş kontit.cnt ++;