JavaScript'teki değişkenlerin kapsamı nedir?

Feb 01 2009

JavaScript'teki değişkenlerin kapsamı nedir? Bir işlevin dışındaki ile aynı kapsama sahipler mi? Ya da önemli mi? Ayrıca, küresel olarak tanımlanmışlarsa değişkenler nerede saklanır?

Yanıtlar

2571 Triptych Feb 01 2009 at 15:58

TLDR

JavaScript'in sözcüksel (statik olarak da adlandırılır) kapsam ve kapanışları vardır. Bu, kaynak koda bakarak bir tanımlayıcının kapsamını söyleyebileceğiniz anlamına gelir.

Dört kapsam şunlardır:

  1. Global - her şey tarafından görülebilir
  2. İşlev - bir işlev içinde görünür (ve alt işlevleri ve blokları)
  3. Blok - bir blok (ve alt blokları) içinde görünür
  4. Modül - bir modül içinde görünür

Global ve modül kapsamının özel durumlarının dışında, değişkenler var(fonksiyon kapsamı), let(blok kapsamı) ve const(blok kapsamı) kullanılarak bildirilir. Diğer tanımlayıcı bildirim biçimlerinin çoğu katı modda blok kapsamına sahiptir.

Genel Bakış

Kapsam, kod tabanının bir tanımlayıcının geçerli olduğu bölgesidir.

Sözcüksel ortam, tanımlayıcı adları ve bunlarla ilişkili değerler arasındaki bir eşlemedir.

Kapsam, sözlü ortamların bağlantılı bir yuvalanmasından oluşur ve yuvadaki her seviye, bir ata yürütme bağlamının sözcüksel ortamına karşılık gelir.

Bu bağlantılı sözcük ortamları bir kapsam "zinciri" oluşturur. Tanımlayıcı çözümlemesi, bu zincir boyunca eşleşen bir tanımlayıcı arama sürecidir.

Tanımlayıcı çözümlemesi yalnızca tek bir yönde gerçekleşir: dışa doğru. Bu şekilde, dış sözcük ortamları, iç sözcük ortamlarını "göremez".

JavaScript'te bir tanımlayıcının kapsamına karar verirken ilgili üç faktör vardır :

  1. Bir tanımlayıcı nasıl beyan edildi
  2. Bir tanımlayıcının beyan edildiği yer
  3. İçinde olsun katı mod veya olmayan katı modda

Tanımlayıcıların bildirilebileceği yollardan bazıları:

  1. var, letveconst
  2. Fonksiyon parametreleri
  3. Yakalama bloğu parametresi
  4. İşlev bildirimleri
  5. Adlandırılmış işlev ifadeleri
  6. Global nesnede örtük olarak tanımlanmış özellikler (yani varkatı olmayan modda eksiklik )
  7. import ifadeler
  8. eval

Bazı konum tanımlayıcıları beyan edilebilir:

  1. Küresel bağlam
  2. İşlev gövdesi
  3. Sıradan blok
  4. Bir kontrol yapısının üst kısmı (ör. Loop, if, while, vb.)
  5. Kontrol yapısı gövdesi
  6. Modüller

Bildirim Stilleri

var

Kullanılarak bildirilen tanımlayıcılar , doğrudan genel bağlamda bildirilmeleri dışında var işlev kapsamına sahiptir ; bu durumda bunlar, genel nesneye özellikler olarak eklenir ve genel kapsama sahiptir. evalİşlevlerde kullanımları için ayrı kurallar vardır .

izin ver ve sabitle

Tanımlayıcıları kullanılarak bildirilmiş letve const blok kapsamına sahip onlar küresel kapsama sahip bu durumda küresel bağlamda, doğrudan beyan edildiği haricinde.

Not: let, constve var tüm askıya alır . Bu, mantıksal tanım konumlarının, kapsayıcı kapsamlarının (blok veya işlev) en üstünde olduğu anlamına gelir. Ancak, değişkenler kullanılarak beyan letve constokumak veya kontrol kaynak kodunda beyanının noktasını geçene kadar tahsis edilemez. Ara dönem, zamansal ölü bölge olarak bilinir.

function f() {
    function g() {
        console.log(x)
    }
    let x = 1
    g()
}
f() // 1 because x is hoisted even though declared with `let`!

İşlev parametresi adları

İşlev parametresi adları, işlev gövdesine göre belirlenir. Bunun biraz karmaşık olduğuna dikkat edin. Varsayılan bağımsız değişkenler olarak bildirilen işlevler, işlevin gövdesine değil, parametre listesine kapanır .

İşlev bildirimleri

İşlev bildirimleri katı modda blok kapsamına ve katı olmayan modda işlev kapsamına sahiptir. Not: Katı olmayan mod, farklı tarayıcıların ilginç tarihsel uygulamalarına dayanan karmaşık bir dizi yeni kuraldır.

Adlandırılmış işlev ifadeleri

Adlandırılmış işlev ifadelerinin kapsamı kendi içindedir (örneğin, özyineleme amacıyla).

Global nesnede örtük olarak tanımlanmış özellikler

Katı olmayan modda, genel nesne kapsam zincirinin en üstünde yer aldığından, genel nesne üzerindeki örtük olarak tanımlanmış özelliklerin genel kapsamı vardır. Katı modda bunlara izin verilmez.

değerlendirme

Gelen evaldizeleri, değişkenler kullanılarak bildirilen vareğer geçerli kapsamda yer veya edilecek evaldolaylı olarak kullanılır küresel nesne üzerinde özellikler olarak,.

Örnekler

Aşağıdaki bir ReferenceError atmak isimlerin çünkü edecek x, yve zfonksiyon hiçbir anlamı dışında var f.

function f() {
    var x = 1
    let y = 1
    const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)

Aşağıdakiler yve için bir ReferenceError atacaktır z, ancak için değil x, çünkü xöğesinin görünürlüğü blok tarafından kısıtlanmamaktadır. Kontrol yapılarının organları tanımlayan Bloklar gibi if, forve while, benzer şekilde hareket eder.

{
    var x = 1
    let y = 1
    const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope

Aşağıda, işlev kapsamı xolduğundan döngünün dışında görülebilir var:

for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)

... bu davranış nedeniyle, vardöngülerde kullanılarak bildirilen değişkenleri kapatırken dikkatli olmanız gerekir . Burada xbildirilen tek bir değişken örneği vardır ve mantıksal olarak döngünün dışında yer alır.

Aşağıdaki 5, beş kez yazdırır ve ardından döngünün dışı 5için altıncı kez yazdırır console.log:

for(var x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop

Aşağıdaki baskılar undefinednedeniyle xblok-kapsamlı olduğunu. Geri aramalar tek tek eşzamansız olarak çalıştırılır. Yeni davranış lether anonim işlev adında farklı bir değişkenin üzerinde kapalı olduğu değişkenler yardımıyla x(o yapmış olabilirler ki aksine var) ve tamsayılar böylece 0aracılığıyla 4yazdırılır .:

for(let x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined

Aşağıdakiler ReferenceError, görünürlüğü xblok tarafından kısıtlanmadığından bir A ATMAZ; ancak, undefineddeğişken başlatılmadığı için (ifade nedeniyle if) yazdırılacaktır .

if(false) {
    var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised

Kullanılarak bir fordöngünün en üstünde bildirilen bir değişken let, döngünün gövdesine göre ayarlanır:

for(let x = 0; x < 10; ++x) {} 
console.log(typeof x) // undefined, because `x` is block-scoped

Aşağıdakiler ReferenceError, görünürlüğü xblok tarafından kısıtlandığı için bir atacaktır :

if(false) {
    let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped

Değişkenler kullanarak ilan var, letya consttüm modüllere kapsamına eklenir:

// module1.js

var x = 0
export function f() {}

//module2.js

import f from 'module1.js'

console.log(x) // throws ReferenceError

Aşağıdakiler, global nesnede bir özellik bildirecektir çünkü varglobal bağlam içinde kullanılarak bildirilen değişkenler global nesneye özellikler olarak eklenir:

var x = 1
console.log(window.hasOwnProperty('x')) // true

letve constgenel bağlamda genel nesneye özellikler ekleme, ancak yine de genel kapsama sahiptir:

let x = 1
console.log(window.hasOwnProperty('x')) // false

İşlev parametrelerinin işlev gövdesinde bildirildiği düşünülebilir:

function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function

Yakalama bloğu parametreleri, yakalama bloğu gövdesine göre ayarlanır:

try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block

Adlandırılmış işlev ifadeleri, yalnızca ifadenin kendisine göre belirlenir:

(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression

Katı olmayan modda, genel nesne üzerinde örtük olarak tanımlanmış özellikler genel kapsamdadır. Katı modda bir hata alırsınız.

x = 1 // implicitly defined property on the global object (no "var"!)

console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true

Katı olmayan modda, işlev bildirimlerinin işlev kapsamı vardır. Katı modda, blok kapsamları vardır.

'use strict'
{
    function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped

Kaputun altında nasıl çalışır

Kapsam, bir tanımlayıcının geçerli olduğu kodun sözlü bölgesi olarak tanımlanır.

JavaScript'te, her işlev nesnesinin içinde oluşturulduğu yürütme bağlamının (yığın çerçevesi) sözcüksel ortamına[[Environment]] bir başvuru olan gizli bir referansı vardır .

Bir işlevi çağırdığınızda gizli [[Call]]yöntem çağrılır. Bu yöntem yeni bir yürütme bağlamı yaratır ve yeni yürütme bağlamı ile işlev nesnesinin sözcüksel ortamı arasında bir bağlantı kurar. Bunu [[Environment]], işlev nesnesi üzerindeki değeri yeni yürütme bağlamının sözcüksel ortamındaki bir dış referans alanına kopyalayarak yapar .

Yeni yürütme bağlamı ile işlev nesnesinin sözcüksel ortamı arasındaki bu bağlantının bir kapatma olarak adlandırıldığına dikkat edin .

Bu nedenle, JavaScript'te kapsam, dış referanslarla bir "zincir" içinde birbirine bağlanmış sözcük ortamları aracılığıyla uygulanır. Bu sözcüksel ortamlar zincirine kapsam zinciri adı verilir ve tanımlayıcı çözümlemesi , zincirde eşleşen bir tanımlayıcı aranarak gerçekleşir .

Daha fazlasını öğrenin .

234 krosenvold Feb 01 2009 at 15:35

Javascript, belirli bir işlevin kapsamını oluşturmak için kapsam zincirlerini kullanır. Tipik olarak bir genel kapsam vardır ve tanımlanan her işlevin kendi iç içe kapsamı vardır. Başka bir işlev içinde tanımlanan herhangi bir işlev, dış işlevle bağlantılı yerel bir kapsama sahiptir. Kapsamı tanımlayan her zaman kaynaktaki konumdur.

Kapsam zincirindeki bir öğe, temelde üst kapsamına bir işaretçiye sahip bir Haritadır.

Bir değişkeni çözümlerken, javascript en iç kapsamda başlar ve dışarıya doğru arama yapar.

110 JonSkeet Feb 01 2009 at 15:31

Global olarak beyan edilen değişkenlerin global bir kapsamı vardır. Bir işlev içinde bildirilen değişkenlerin kapsamı bu işlevin kapsamına alınır ve aynı ada sahip global değişkenlerin gölgelenir.

(Eminim gerçek JavaScript programcılarının diğer yanıtlarda gösterebilecekleri pek çok incelik vardır. Özellikle , herhangi bir zamanda tam olarak ne anlama geldiğiyle ilgili bu sayfaya rastladım this. Umarım bu daha fazla giriş bağlantısı başlamanız için yeterlidir. .)

77 JohnSlegers Feb 24 2016 at 01:51

Eski okul JavaScript

Geleneksel olarak, JavaScript gerçekten yalnızca iki tür kapsama sahiptir:

  1. Global Kapsam : Değişkenler, uygulamanın başlangıcından itibaren uygulama boyunca bilinir (*)
  2. İşlevsel Kapsam : Değişkenler , işlevin başlangıcından (*) itibaren bildirildikleri işlev içinde bilinir.

Halihazırda farkı açıklayan birçok başka cevap olduğu için bu konuyu detaylandırmayacağım.


Modern JavaScript

En son JavaScript gözlük şimdi de üçüncü bir kapsam sağlar:

  1. Blok Kapsamı : Tanımlayıcılar, içinde bildirildikleri kapsamın tepesinden "bilinir" , ancak beyanlarının satırından sonrasına kadar atanamaz veya referans alınamaz (okunamaz). Bu ara döneme "geçici ölü bölge" denir.

Blok kapsamı değişkenlerini nasıl oluşturabilirim?

Geleneksel olarak, değişkenlerinizi şu şekilde oluşturursunuz:

var myVariable = "Some text";

Blok kapsamı değişkenleri şu şekilde oluşturulur:

let myVariable = "Some text";

Öyleyse işlevsel kapsam ile blok kapsamı arasındaki fark nedir?

İşlevsel kapsam ve blok kapsamı arasındaki farkı anlamak için aşağıdaki kodu göz önünde bulundurun:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Burada, değişkenimizin jsadece ilk for döngüsünde bilindiğini, öncesinde ve sonrasında olmadığını görebiliriz. Yine de değişkenimiz itüm fonksiyonda bilinir.

Ayrıca, blok kapsamlı değişkenlerin kaldırılmadıkları için bildirilmeden önce bilinmediklerini göz önünde bulundurun. Aynı blok kapsamlı değişkeni aynı blok içinde yeniden açıklamanıza da izin verilmez. Bu, blok kapsamlı değişkenleri, genel veya işlevsel kapsamlı değişkenlerden daha az hataya yatkın hale getirir, bunlar kaldırılır ve birden çok bildirim durumunda herhangi bir hata üretmez.


Bugün blok kapsamı değişkenlerini kullanmak güvenli midir?

Bugün kullanmanın güvenli olup olmadığı ortamınıza bağlıdır:

  • Sunucu tarafı JavaScript kodu ( Node.js ) yazıyorsanız, letifadeyi güvenle kullanabilirsiniz .

  • İstemci tarafı JavaScript kodu yazıyorsanız ve tarayıcı tabanlı bir aktarıcı ( Traceur veya babel-bağımsız gibi ) kullanıyorsanız, letifadeyi güvenle kullanabilirsiniz , ancak kodunuz muhtemelen performans açısından ideal olmaktan başka her şey olacaktır.

  • İstemci tarafı JavaScript kodu yazıyorsanız ve Düğüm tabanlı bir aktarıcı kullanıyorsanız ( izleyici kabuk komut dosyası veya Babel gibi ), letifadeyi güvenle kullanabilirsiniz . Tarayıcınız yalnızca aktarılan kod hakkında bilgi sahibi olacağından, performans sakıncaları sınırlandırılmalıdır.

  • İstemci tarafı JavaScript kodu yazıyorsanız ve bir aktarıcı kullanmıyorsanız, tarayıcı desteğini dikkate almanız gerekir.

    Bunlar hiç desteklemeyen bazı tarayıcılardır let:

    • Internet explorer 10 ve altı
    • Firefox 43 ve altı
    • Safari 9 ve altı
    • Android tarayıcı 4 ve altı
    • Opera 27 ve altı
    • Chome 40 ve altı
    • HERHANGİ BİR Opera Mini & Blackberry Browser sürümü


Tarayıcı desteği nasıl takip edilir

letBu cevabı okurken hangi tarayıcıların beyanı desteklediğine dair güncel bir genel bakış için bu Can I Usesayfaya bakın .


(*) Genel ve işlevsel kapsamlı değişkenler, JavaScript değişkenleri kaldırıldığı için bildirilmeden önce başlatılabilir ve kullanılabilir . Bu, bildirimlerin her zaman kapsamın en üstünde olduğu anlamına gelir.

40 geowa4 Feb 01 2009 at 15:48

İşte bir örnek:

<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal(); 
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  }; 

}

</script>

Kapanışları ve bunları özel üye yapmak için nasıl kullanacağınızı araştırmak isteyeceksiniz .

31 JamesMcMahon May 16 2012 at 00:38

Anahtar, anladığım kadarıyla, Javascript'in daha yaygın C blok kapsamına kıyasla işlev düzeyinde kapsam belirlemesine sahip olmasıdır.

İşte konuyla ilgili güzel bir makale.

26 kennytm Apr 06 2010 at 18:19

"Javascript 1.7" 'de (Mozilla'nın Javascript uzantısı) blok kapsamı değişkenleri aşağıdaki letifadeyle de bildirilebilir :

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4
25 TravisJ Sep 15 2015 at 03:29

Başlangıçta Brendan Eich tarafından tasarlandığında JavaScript'te kapsam belirleme fikri , HyperCard komut dosyası dili HyperTalk'tan geldi .

Bu dilde, ekranlar bir dizi dizin kartına benzer şekilde yapıldı. Arka plan olarak adlandırılan bir ana kart vardı. Şeffaftı ve alt kart olarak görülebilir. Bu temel karttaki herhangi bir içerik, üstüne yerleştirilen kartlarla paylaşıldı. En üste yerleştirilen her kartın, önceki karttan öncelikli olan kendi içeriği vardı, ancak istenirse yine de önceki kartlara erişebiliyordu.

JavaScript kapsam belirleme sistemi tam olarak bu şekilde tasarlanmıştır. Sadece farklı isimleri var. JavaScript'teki kartlar Yürütme Bağlamları ECMA olarak bilinir . Bu bağlamların her biri üç ana bölümden oluşmaktadır. Değişken bir ortam, sözlü bir ortam ve bir bu bağlama. Kart referansına geri dönersek, sözcüksel ortam yığında daha düşük olan önceki kartların tüm içeriğini içerir. Geçerli bağlam, yığının en üstündedir ve orada bildirilen herhangi bir içerik, değişken ortamda depolanacaktır. Adlandırma çakışması durumunda değişken ortam öncelikli olacaktır.

Bu bağlama, içeren nesneyi işaret edecektir. Bazen kapsamlar veya yürütme bağlamları, kapsayıcı nesnenin windowveya bir yapıcı işlevin olabileceği bildirilmiş bir işlevde olduğu gibi, içeren nesne değişmeden değişir .

Bu yürütme bağlamları, kontrolün aktarıldığı her zaman oluşturulur. Kontrol, kod yürütülmeye başladığında aktarılır ve bu, öncelikle işlev yürütmeden yapılır.

Teknik açıklama budur. Pratikte, JavaScript'te bunu hatırlamak önemlidir.

  • Kapsamlar teknik olarak "Yürütme Bağlamları" dır
  • Bağlamlar, değişkenlerin depolandığı bir ortam yığını oluşturur
  • Yığının üst kısmı önceliklidir (alt kısım genel bağlamdır)
  • Her işlev bir yürütme bağlamı oluşturur (ancak her zaman bu bağlamda yeni değildir)

Bunu, bu sayfadaki önceki örneklerden birine (5. "Kapanış") uygulayarak, yürütme bağlamları yığınını izlemek mümkündür. Bu örnekte, yığında üç bağlam vardır. Dış bağlamla, var six ile çağrılan hemen çağrılan işlevdeki bağlam ve var six'in hemen çağrılan işlevinin içindeki döndürülen işlevdeki bağlamla tanımlanırlar.

i ) Dış bağlam. A = 1 değişken ortamına sahiptir
ii ) IIFE bağlamı, a = 1 sözlü ortamına sahiptir, ancak yığında öncelikli olan a = 6 değişken ortamına sahiptir
iii ) Döndürülen işlev bağlamı, sözlü bir a = 6 ortamı ve bu, çağrıldığında uyarıda başvurulan değerdir.

17 GerardONeill Oct 25 2013 at 07:41

1) Global bir kapsam, bir fonksiyon kapsamı ve with ve catch kapsamları vardır. Değişkenler için genel olarak bir 'blok' seviyesi kapsamı yoktur - with ve catch deyimleri bloklarına isimler ekler.

2) Kapsamlar, işlevler tarafından genel kapsamın sonuna kadar yuvalanmıştır.

3) Özellikler prototip zincirinden geçilerek çözülür. With ifadesi, nesne özellik adlarını with bloğu tarafından tanımlanan sözcük kapsamına getirir.

DÜZENLEME: ECMAAScript 6 (Harmony), let'i desteklemek için tasarlanmıştır ve Chrome'un bir "uyum" bayrağına izin verdiğini biliyorum, bu nedenle belki de desteklemektedir ..

Blok düzeyinde kapsam belirleme için bir destek olalım, ancak bunun gerçekleşmesi için anahtar kelimeyi kullanmanız gerekir.

DÜZENLEME: Benjamin'in yorumlardaki with ve catch ifadelerine işaret etmesine dayanarak, gönderiyi düzenledim ve daha fazlasını ekledim. Hem ile ve yakalamak ifadeleri kendi bloklar halinde değişkenleri tanıtmak ve bu ise bir blok kapsamı. Bu değişkenler, kendilerine iletilen nesnelerin özelliklerine göre adlandırılır.

 //chrome (v8)

 var a = { 'test1':'test1val' }
 test1   // error not defined
 with (a) { var test1 = 'replaced' }
 test1   // undefined
 a       // a.test1 = 'replaced'

DÜZENLEME: Açıklayıcı örnek:

test1'in kapsamı with bloğuna ayarlanır, ancak a.test1'e diğer ad verilir. 'Var test1', a'nın bir özelliği olmadığı sürece üst sözcük bağlamında (fonksiyon veya genel) yeni bir test1 değişkeni yaratır - ki bu.

Eyvah! 'With' kullanırken dikkatli olun - tıpkı değişken işlevde zaten tanımlanmışsa, var'ın noop olması gibi, nesneden içe aktarılan adlar açısından da noop'dur! Zaten tanımlanmakta olan isme ilişkin küçük bir uyarı, bunu çok daha güvenli hale getirecektir. Şahsen bu yüzden asla kullanmayacağım.

9 austincheney Mar 22 2013 at 00:31

JavaScript'e yeni başlayan birçok kişinin, kalıtımın varsayılan olarak dilde mevcut olduğunu ve şu ana kadar tek kapsamın işlev kapsamının olduğunu anlamakta güçlük çektiğini gördüm. Geçen yılın sonunda yazdığım JSPretty adlı güzelleştiriciye bir uzantı sağladım. Özellik renkleri işlevi, koddaki kapsamı ve her zaman bu kapsamda bildirilen tüm değişkenlerle bir rengi ilişkilendirir. Kapanış, bir kapsamdan bir renge sahip bir değişken farklı bir kapsamda kullanıldığında görsel olarak gösterilir.

Özelliği şurada deneyin:

  • http://prettydiff.com/jspretty.xhtml?c=white&jsscope

Şurada bir demo izleyin:

  • http://prettydiff.com/jspretty.xhtml?c=white&jsscope&s=http://prettydiff.com/lib/markup_beauty.js

Kodu şu adreste görüntüleyin:

  • http://prettydiff.com/lib/jspretty.js
  • https://github.com/austincheney/Pretty-Diff/blob/master/lib/jspretty.js

Şu anda bu özellik, 16 iç içe işlev derinliği için destek sunuyor, ancak şu anda genel değişkenleri renklendirmiyor.

9 Anshul Sep 22 2014 at 03:44

JavaScript'in yalnızca iki tür kapsamı vardır:

  1. Global Kapsam : Global, pencere düzeyinde kapsamdan başka bir şey değildir Burada, değişken uygulama boyunca mevcuttur.
  2. Fonksiyonel Kapsam : varAnahtar kelimeli bir fonksiyon içerisinde bildirilen değişkenin fonksiyonel kapsamı vardır.

Bir işlev çağrıldığında, bir değişken kapsam nesnesi oluşturulur (ve kapsam zincirine dahil edilir) ve ardından JavaScript'teki değişkenler gelir.

        a = "global";
         function outer(){ 
              b = "local";
              console.log(a+b); //"globallocal"
         }
outer();

Kapsam zinciri ->

  1. Pencere düzeyi - ave outerişlev, kapsam zincirinde en üst düzeydedir.
  2. dış işlev yeni olarak çağrıldığında variable scope object(ve kapsam zincirine dahil edildiğinde) biçinde değişken ile eklendi .

Şimdi, bir değişken agerekli olduğunda, önce en yakın değişken kapsamını arar ve değişken yoksa, daha sonra değişken kapsam zincirinin bir sonraki nesnesine geçer. Bu durumda pencere seviyesidir.

9 JamesDrinkard Mar 30 2016 at 20:33

Diğer yanıtlara ek olarak, kapsam, bildirilen tüm tanımlayıcıların (değişkenlerin) bir arama listesidir ve bunların şu anda çalışan kod tarafından nasıl erişilebilir olduğuna dair katı bir kurallar dizisini zorunlu kılar. Bu arama, bir LHS (sol taraf) referansı olan değişkene atama amaçlı olabilir veya bir RHS (sağ taraf) referansı olan değerini geri alma amacıyla olabilir. Bu aramalar, JavaScript motorunun kodu derlerken ve yürütürken dahili olarak yaptığı şeydir.

Bu açıdan bakıldığında, Kyle Simpson'ın Scopes and Closures e-kitabında bulduğum bir resmin yardımcı olacağını düşünüyorum:

E-kitabından alıntı:

Bina, programımızın iç içe geçmiş kapsam kural kümesini temsil eder. Binanın birinci katı, nerede olursanız olun, şu anda yürütmekte olduğunuz alanı temsil eder. Binanın en üst seviyesi küresel kapsamdır. LHS ve RHS referanslarını mevcut katınıza bakarak ve bulamazsanız, asansörü bir sonraki kata götürerek, oraya, sonra bir sonraki kata bakarak vb. Çözersiniz. En üst kata (küresel kapsam) ulaştığınızda, ya aradığınızı bulursunuz ya da bulamazsınız. Ama ne olursa olsun durmalısın.

Kayda değer bir nokta, "Kapsam araması, ilk eşleşmeyi bulduğunda durur".

Bu "kapsam seviyeleri" fikri, iç içe geçmiş bir işlevde aranıyorsa, yeni oluşturulan bir kapsamla "bunun" neden değiştirilebileceğini açıklar. İşte tüm bu ayrıntılara giren bir bağlantı, JavaScript kapsamı hakkında bilmek istediğiniz her şey

8 YeasinAbedinSiam Oct 18 2014 at 16:54

kodu çalıştırın. umarım bu kapsam belirleme hakkında bir fikir verir

Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
    Name: 'object data',
    f: function(){
        alert(this.Name);
    }
};

myObj.newFun = function(){
    alert(this.Name);
}

function testFun(){
    alert("Window Scope : " + window.Name + 
          "\nLocal Scope : " + Name + 
          "\nObject Scope : " + this.Name + 
          "\nCurrent document Scope : " + document.Name
         );
}


testFun.call(myObj);
})(window,document);
8 JhankarMahbub Jun 24 2014 at 21:12

Global Kapsam:

Küresel değişkenler tam olarak küresel yıldızlar gibidir (Jackie Chan, Nelson Mandela). Bunlara uygulamanızın herhangi bir bölümünden erişebilirsiniz (değeri alabilir veya ayarlayabilirsiniz). Küresel işlevler, küresel olaylar gibidir (Yeni Yıl, Noel). Bunları uygulamanızın herhangi bir bölümünden çalıştırabilirsiniz (çağırabilirsiniz).

//global variable
var a = 2;

//global function
function b(){
   console.log(a);  //access global variable
}

Yerel Kapsam:

ABD'deyseniz, ünlü ünlü Kim Kardashian'ı tanıyor olabilirsiniz (bir şekilde magazin dergilerini yapmayı başarıyor). Ancak ABD dışındaki insanlar onu tanımayacak. Bölgesine bağlı yerel bir yıldızdır.

Yerel değişkenler yerel yıldızlar gibidir. Bunlara yalnızca kapsam içinde erişebilir (değeri alabilir veya ayarlayabilirsiniz). Yerel bir işlev, yerel olaylar gibidir - yalnızca bu kapsamın içinde gerçekleştirebilirsiniz (kutlayabilirsiniz). Bunlara kapsam dışından erişmek isterseniz, bir referans hatası alırsınız.

function b(){
   var d = 21; //local variable
   console.log(d);

   function dog(){  console.log(a); }
     dog(); //execute local function
}

 console.log(d); //ReferenceError: dddddd is not defined    

Kapsamın derinlemesine anlaşılması için bu makaleye bakın

6 jackbean818 Oct 29 2015 at 23:12

NEREDEYSE yalnızca iki tür JavaScript kapsamı vardır:

  • her bir değişken bildiriminin kapsamı, en kısa sürede kapsayan işlevle ilişkilendirilir
  • bir var bildirimi için çevreleyen bir işlev yoksa, bu genel kapsamdır

Bu nedenle, işlevler dışındaki herhangi bir blok yeni bir kapsam oluşturmaz. Bu, for-döngülerinin neden dış kapsamlı değişkenlerin üzerine yazdığını açıklar:

var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

Bunun yerine işlevleri kullanmak:

var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

İlk örnekte, blok kapsamı olmadığı için, başlangıçta bildirilen değişkenlerin üzerine yazılmıştır. İkinci örnekte, işlev nedeniyle yeni bir kapsam vardı, bu nedenle başlangıçta bildirilen değişkenler GÖLGELENDİ ve üzerine yazılmadı.

Aşağıdakiler dışında JavaScript kapsamı açısından bilmeniz gereken neredeyse her şey bu kadardır:

  • try / catch, SADECE istisna değişkeninin kendisi için yeni kapsam sunar, diğer değişkenlerin yeni kapsamı yoktur.
  • with-clause görünüşe göre başka bir istisnadır, ancak with-clause kullanılması kesinlikle önerilmez (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with)

Dolayısıyla, JavaScript kapsamının her zaman sezgisel olmasa da aslında son derece basit olduğunu görebilirsiniz. Dikkat edilmesi gereken birkaç nokta:

  • var bildirimleri kapsamın en üstüne kaldırılır. Bu, var bildirimi nerede olursa olsun, derleyiciye varlığın kendisi üstte gerçekleşiyormuş gibi olduğu anlamına gelir.
  • aynı kapsamdaki çoklu değişken bildirimleri birleştirilir

Yani bu kod:

var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

eşdeğerdir:

var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

Bu, sezgiye aykırı görünebilir, ancak zorunlu bir dil tasarımcısının bakış açısından anlamlıdır.

4 Gibolt Sep 27 2017 at 03:23

Modern Js, ES6 +, ' const' ve ' let'

Diğer büyük dillerin çoğunda olduğu gibi, oluşturduğunuz her değişken için blok kapsamını kullanıyor olmalısınız. varolduğunu eskimiş . Bu, kodunuzu daha güvenli ve bakımı daha kolay hale getirir.

constvakaların% 95'i için kullanılmalıdır . Değişken referansının değişmemesini sağlar. Dizi, nesne ve DOM düğümü özellikleri değişebilir ve muhtemelen değişmelidir const.

letyeniden atanması beklenen herhangi bir değişken için kullanılmalıdır. Buna bir for döngüsü dahildir. Değeri başlatmanın ötesinde değiştirirseniz, kullanın let.

Blok kapsamı, değişkenin yalnızca bildirildiği parantez içinde kullanılabileceği anlamına gelir. Bu, kapsamınız dahilinde oluşturulan anonim işlevler dahil olmak üzere dahili kapsamları kapsar.

3 Mig82 Aug 11 2013 at 00:37

Bu ilginç örneği deneyin. Aşağıdaki örnekte a, 0'da ilklendirilmiş bir sayısal olsaydı, 0'ı ve sonra 1'i görürsünüz. A bir nesnedir ve javascript f1'e bir kopyası yerine a işaretçisi iletir. Sonuç, her iki seferde de aynı uyarıyı almanızdır.

var a = new Date();
function f1(b)
{
    b.setDate(b.getDate()+1);
    alert(b.getDate());
}
f1(a);
alert(a.getDate());
3 koredalin Jul 12 2015 at 01:03

JS'de yalnızca işlev kapsamları vardır. Kapsamları engellemeyin! Neyin kaldırıldığını da görebilirsiniz.

var global_variable = "global_variable";
var hoisting_variable = "global_hoist";

// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);

if (true) {
    // The variable block will be global, on true condition.
    var block = "block";
}
console.log("global_scope: - block: " + block);

function local_function() {
    var local_variable = "local_variable";
    console.log("local_scope: - local_variable: " + local_variable);
    console.log("local_scope: - global_variable: " + global_variable);
    console.log("local_scope: - block: " + block);
    // The hoisting_variable is undefined at the moment.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);

    var hoisting_variable = "local_hoist";
    // The hoisting_variable is now set as a local one.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}

local_function();

// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
2 mrmaclean89 Sep 17 2017 at 05:35

Anladığım kadarıyla 3 kapsam var: küresel kapsam, küresel olarak mevcut; yerel kapsam, bloklardan bağımsız olarak tüm işlev için kullanılabilir; ve blok kapsamı, yalnızca üzerinde kullanıldığı blok, ifade veya ifade için kullanılabilir. Global ve yerel kapsam, bir işlev içinde veya dışında 'var' anahtar sözcüğü ile belirtilir ve blok kapsamı 'let' anahtar sözcüğü ile gösterilir.

Yalnızca küresel ve yerel kapsam olduğuna inananlar için, lütfen Mozilla'nın JS'deki blok kapsamının nüanslarını açıklayan tam bir sayfaya sahip olduğunu açıklayın.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

2 AbdurRahman Nov 01 2017 at 16:16

JavaScript'te iki tür kapsam vardır:

  • Yerel kapsam
  • Global kapsam

Aşağıdaki işlevin yerel bir kapsam değişkeni vardır carName. Ve bu değişkene işlevin dışından erişilemez.

function myFunction() {
    var carName = "Volvo";
    alert(carName);
    // code here can use carName
}

Below Class, Global kapsam değişkenine sahiptir carName. Ve bu değişkene sınıfın her yerinden erişilebilir.

class {

    var carName = " Volvo";

    // code here can use carName

    function myFunction() {
        alert(carName);
        // code here can use carName 
    }
}
2 CertainPerformance Dec 31 2019 at 09:50

Henüz açıklanmayan ve ön uç kodlayıcıların sıklıkla karşılaştığı çok yaygın bir sorun, HTML'deki satır içi bir olay işleyicisi tarafından görülebilen kapsamdır - örneğin,

<button onclick="foo()"></button>

Bir on*özniteliğin başvurabileceği değişkenlerin kapsamı şunlardan biri olmalıdır :

  • global (satır içi işleyicilerle çalışmak neredeyse her zaman global değişkenlere başvurur)
  • belgenin bir özelliği (örneğin, querySelectorbağımsız bir değişken olarak document.querySelector; nadiren)
  • işleyicinin bağlı olduğu öğenin bir özelliği (yukarıdaki gibi; nadir)

Aksi takdirde, işleyici çağrıldığında bir ReferenceError hatası alırsınız. Bu nedenle, örneğin, satır içi işleyici içinde tanımlanan bir işleve başvurursawindow.onload veya $(function() {satır içi işleyici yalnızca genel kapsamdaki değişkenlere başvurabileceği ve işlev genel olmadığı için başvuru başarısız olur:

window.addEventListener('DOMContentLoaded', () => {
  function foo() {
    console.log('foo running');
  }
});
<button onclick="foo()">click</button>

Özellikleri documentve işleyici içi yükleyiciler çağrılır için de içi işleyicileri içinde bağımsız değişkenler olarak ifade edilebilir bağlı olan elementin özelliklerinin içinde iki withblok için, bir documentelemanın için bir. Bu işleyicilerdeki değişkenlerin kapsam zinciri son derece sezgisel değildir ve çalışan bir olay işleyicisi muhtemelen bir işlevin global olmasını gerektirecektir (ve gereksiz küresel kirlilikten muhtemelen kaçınılmalıdır ).

Satır içi işleyicilerdeki kapsam zinciri çok tuhaf olduğundan ve satır içi işleyicilerin çalışması için küresel kirlilik gerektirdiğinden ve satır içi işleyiciler bazen argümanları iletirken çirkin dizelerden kaçmayı gerektirdiğinden, bunlardan kaçınmak muhtemelen daha kolaydır. Bunun yerine, addEventListenerHTML biçimlendirmesi yerine Javascript kullanarak (ile olduğu gibi ) olay işleyicileri ekleyin .

function foo() {
  console.log('foo running');
}
document.querySelector('.my-button').addEventListener('click', foo);
<button class="my-button">click</button>


Farklı bir notta, <script>en üst seviyede çalışan normal etiketlerin aksine , ES6 modülleri içindeki kod kendi özel kapsamında çalışır. Normal bir <script>etiketin üstünde tanımlanan bir değişken globaldir, bu nedenle ona aşağıdaki gibi diğer <script>etiketlerde başvurabilirsiniz :

<script>
const foo = 'foo';
</script>
<script>
console.log(foo);
</script>

Ancak bir ES6 modülünün en üst seviyesi küresel değildir . ES6 modülünün tepesinde bildirilen bir değişken, değişken açıkça belirtilmediği exportveya global nesnenin bir özelliğine atanmadığı sürece yalnızca o modülün içinde görünür olacaktır .

<script type="module">
const foo = 'foo';
</script>
<script>
// Can't access foo here, because the other script is a module
console.log(typeof foo);
</script>

Bir ES6 modülünün en üst seviyesi, normalde en üst seviyedeki bir IIFE'nin iç kısmına benzer <script>. Modül, global olan herhangi bir değişkene başvurabilir ve modül açıkça onun için tasarlanmadıkça hiçbir şey modülün içindeki hiçbir şeye referans veremez.

1 WillemvanderVeen Sep 30 2018 at 16:23

ES5 ve daha önce:

Javascript'teki değişkenler başlangıçta (ön ES6) sözcüksel olarak işlev kapsamına alındı . Sözcüksel kapsamlı terimi, koda 'bakarak' değişkenlerin kapsamını görebileceğiniz anlamına gelir.

varAnahtar kelimeyle bildirilen her değişken , işlevin kapsamı altındadır. Ancak, bu işlev içinde başka işlev bildirilirse, bu işlevler dış işlevlerin değişkenlerine erişebilir. Buna kapsam zinciri denir . Aşağıdaki şekilde çalışır:

  1. Bir işlev bir değişken değeri çözümlemeye çalıştığında, önce kendi kapsamına bakar. Bu, işlev gövdesidir, yani küme parantezleri {} arasındaki her şey ( bu kapsamdaki diğer işlevlerin içindeki değişkenler hariç ).
  2. Değişkeni fonksiyon gövdesi içinde bulamazsa zincire tırmanır ve fonksiyonun tanımlandığı fonksiyondaki değişken kapsamına bakar . Sözcük kapsamı ile kastedilen budur, bu işlevin nerede tanımlandığını kodda görebilir ve böylece kapsam zincirini yalnızca koda bakarak belirleyebiliriz.

Misal:

// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';

function outerFunc () {
 // outerFunc scope
 var foo = 'outerFunc';
 var foobar = 'outerFunc';
 innerFunc();
 
 function innerFunc(){
 // innerFunc scope
  var foo = 'innerFunc';
  console.log(foo);
  console.log(bar);
  console.log(foobar);
  }
}

outerFunc();

Ne değişkenleri oturum çalışırken olur foo, barve foobarkonsola şudur:

  1. Konsola foo kaydetmeye çalışıyoruz, foo işlevin içinde bulunabilir innerFunc. Bu nedenle, foo'nun değeri dizeye çözümlenir innerFunc.
  2. Konsola bar kaydetmeye çalışıyoruz, bar işlevin içinde bulunamıyor innerFunc. Bu nedenle, kapsam zincirine tırmanmamız gerekiyor . Önce fonksiyonun innerFunctanımlandığı dış fonksiyona bakarız . İşlev budur outerFunc. Kapsamında, outerFunc'externalFunc' dizesini tutan değişken bar'ı bulabiliriz.
  3. foobar innerFunc içinde bulunamıyor. . Bu nedenle, kapsam zincirini iç Fonksiyon kapsamına tırmanmamız gerekiyor . Burada da bulunamıyor, küresel kapsamda başka bir seviyeye tırmanıyoruz (yani en dış kapsam). Burada 'global' dizesini tutan değişken foobar'ı buluyoruz. Kapsam zincirine tırmandıktan sonra değişkeni bulamazsa, JS motoru bir referenceError atar .

ES6 (ES 2015) ve daha eski:

Aynı sözcüksel kapsam ve kapsam alanı kavramları hala geçerlidir ES6. Ancak değişkenleri tanımlamanın yeni yolları tanıtıldı. Aşağıdakiler vardır:

  • let: blok kapsamlı bir değişken oluşturur
  • const: başlatılması gereken ve yeniden atanamayan blok kapsamlı bir değişken oluşturur

Arasındaki en büyük fark varve let/ constolmasıdır varfonksiyonu ise kapsamlı olan let/ constblok kapsamlı bulunmaktadır. İşte bunu açıklamak için bir örnek:

let letVar = 'global';
var varVar = 'global';

function foo () {
  
  if (true) {
    // this variable declared with let is scoped to the if block, block scoped
    let letVar = 5;
    // this variable declared with let is scoped to the function block, function scoped
    var varVar = 10;
  }
  
  console.log(letVar);
  console.log(varVar);
}


foo();

Yukarıdaki örnekte letVar global değeri günlüğe kaydeder çünkü ile bildirilen değişkenler letblok kapsamlıdır. Kendi bloklarının dışında var olmaya son verirler, bu nedenle değişkene if bloğunun dışından erişilemez.

VivekMehta Dec 15 2017 at 12:31

EcmaScript5'te, esas olarak iki kapsam vardır, yerel kapsam ve genel kapsam, ancak EcmaScript6'da esas olarak üç kapsamımız, yerel kapsam, genel kapsam ve blok kapsamı adı verilen yeni bir kapsam vardır .

Blok kapsamı örneği: -

for ( let i = 0; i < 10; i++)
{
 statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
DavaakhuuErdenekhuu Feb 09 2018 at 22:37

ECMAScript 6, let ve const anahtar sözcüklerini tanıttı. Bu anahtar sözcükler, var anahtar sözcüğü yerine kullanılabilir. Var anahtar kelimesinin tersine, let ve const anahtar sözcükleri, blok ifadeleri içindeki yerel kapsam bildirimini destekler.

var x = 10
let y = 10
const z = 10
{
  x = 20
  let y = 20
  const z = 20
  {
    x = 30
    // x is in the global scope because of the 'var' keyword
    let y = 30
    // y is in the local scope because of the 'let' keyword
    const z = 30
    // z is in the local scope because of the 'const' keyword
    console.log(x) // 30
    console.log(y) // 30
    console.log(z) // 30
  }
  console.log(x) // 30
  console.log(y) // 20
  console.log(z) // 20
}

console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
AhmedKhashaba May 25 2020 at 23:11

Kabul edilen cevabı gerçekten beğendim ama şunu eklemek istiyorum:

Kapsam, bildirilen tüm tanımlayıcıların (değişkenlerin) bir arama listesini toplar ve korur ve bunların şu anda yürütülen kod tarafından nasıl erişilebilir olduğuna dair katı bir kurallar dizisini uygular.

Kapsam, değişkenleri tanımlayıcı adlarına göre aramak için kullanılan bir kurallar kümesidir.

  • Bir değişken anlık kapsamda bulunamazsa, Engine, bulunana kadar veya en dıştaki (aka, genel) kapsama ulaşılıncaya kadar devam ederek sonraki dış kapsama alanına danışır.
  • Bir değişkenin (tanımlayıcının) nerede ve nasıl aranacağını belirleyen kurallar kümesidir. Bu arama, bir LHS (sol taraf) referansı olan değişkene atama amacıyla olabilir veya bir RHS (sağ taraf) referansı olan değerini geri alma amacıyla olabilir. .
  • LHS referansları, atama işlemlerinden kaynaklanır. Kapsamla ilgili atamalar, = operatörüyle veya işlev parametrelerine (atama) bağımsız değişkenler iletilerek gerçekleştirilebilir.
  • JavaScript motoru, kodu çalıştırmadan önce derler ve bunu yaparken var a = 2 gibi ifadeleri böler. iki ayrı adımda: 1. İlk olarak, bu kapsamda bildirmek için var a. Bu, kodun çalıştırılmasından önce başlangıçta gerçekleştirilir. 2. Daha sonra, değişkeni (LHS referansı) aramak ve bulunursa ona atamak için a = 2.
  • Hem LHS hem de RHS referans aramaları, şu anda yürütülen kapsamda başlar ve gerekirse (yani, orada aradıklarını bulamazlar), iç içe geçmiş kapsamda, bir kapsamda (kat ) bir seferde, global (en üst kat) olana kadar tanımlayıcıyı arar ve durur, bulur veya bulmaz. Doldurulmamış RHS referansları, ReferenceError'ın atılmasına neden olur. Doldurulmamış LHS referansları, otomatik, dolaylı olarak bu adın genel olarak oluşturulmuş (Katı Modda değilse) veya bir Referans Hatası (Katı Modda ise) ile sonuçlanır.
  • kapsam, her biri tanımlayıcıların (değişkenler, işlevler) bildirildiği bir kap veya kova görevi gören bir dizi "baloncuk" dan oluşur. Bu kabarcıklar düzgün bir şekilde birbirlerinin içine yuva yapar ve bu yuva, yazar zamanında tanımlanır.