|
| 1 | +## Kapsamlar ve İsim Uzayları |
| 2 | + |
| 3 | +JavaScript'te birbiri ile eşleşen ayraçlar kullanılmasına karşın blok |
| 4 | +kapsamı **bulunmaz**; bu nedenle, dilde sadece *fonksiyon kapsamı* mevcuttur. |
| 5 | + |
| 6 | + function test() { // fonksiyon kapsamı |
| 7 | + for(var i = 0; i < 10; i++) { // kapsam değil |
| 8 | + // sayaç |
| 9 | + } |
| 10 | + console.log(i); // 10 |
| 11 | + } |
| 12 | + |
| 13 | +> **Not:** Bir değer atama, `return` ifadesi veya fonksiyon argümanı olarak |
| 14 | +> kullanıldığında `{...}` notasyonu bir nesne değişmezi olarak **değil** |
| 15 | +> blok ifade olarak değerlendirilir. Bu özellik |
| 16 | +> [otomatik noktalı virgül ilavesi](#core.semicolon) ile birleştiğinde fark |
| 17 | +> edilmesizor hatalara neden olabilir. |
| 18 | +
|
| 19 | +JavaScript'te isim uzayları kavramı da bulunmaz, tanımlanan herşey tek bir |
| 20 | +*genel olarak paylaşılmış* bir isim uzayının içindedir. |
| 21 | + |
| 22 | +Bir değişkene erişildiğinde, JavaScript değişkenin tanımını bulana dek yukarıya |
| 23 | +doğru tüm kapsamlara bakar. Genel kapsama ulaşıldığı halde hala değişkenin |
| 24 | +tanımı bulanamamışsa bir `ReferenceError` hatası oluşur. |
| 25 | + |
| 26 | +### Genel değişkenler felaketi |
| 27 | + |
| 28 | + // A programı |
| 29 | + foo = '42'; |
| 30 | + |
| 31 | + // B programı |
| 32 | + var foo = '42' |
| 33 | + |
| 34 | +Yukarıdaki iki program birbirinden **farklıdır**. A programında *genel* kapsamda |
| 35 | +bir `foo` değişkeni tanımlanmıştır, B programındaki `foo` değişkeni ise *mevcut* |
| 36 | +kapsamda tanımlanmıştır. |
| 37 | + |
| 38 | +Bu iki tanımlamanın birbirinden **farklı** *etkileri* olacaktır, `var` anahtar |
| 39 | +kelimesini kullanmamanın önemli sonuçları olabilir. |
| 40 | + |
| 41 | + // genel kapsam |
| 42 | + var foo = 42; |
| 43 | + function test() { |
| 44 | + // lokal kapsam |
| 45 | + foo = 21; |
| 46 | + } |
| 47 | + test(); |
| 48 | + foo; // 21 |
| 49 | + |
| 50 | +`test` fonksiyonun içinde `var` anahtar kelimesinin atlanması genel kapsamdaki |
| 51 | +`foo` değişkeninin değerini değiştirecektir. İlk bakışta bu önemsiz gibi görünse |
| 52 | +de, binlerce satırlık bir programda `var` kullanılmaması korkunç ve takibi güç |
| 53 | +hatalara neden olacaktor. |
| 54 | + |
| 55 | + // genel kapsam |
| 56 | + var items = [/* bir dizi */]; |
| 57 | + for(var i = 0; i < 10; i++) { |
| 58 | + subLoop(); |
| 59 | + } |
| 60 | + |
| 61 | + function subLoop() { |
| 62 | + // subLoop fonksiyonun kapsamı |
| 63 | + for(i = 0; i < 10; i++) { // var kullanılmamış |
| 64 | + // do amazing stuff! |
| 65 | + } |
| 66 | + } |
| 67 | + |
| 68 | +Dışarıdaki döngüden `subLoop` fonksiyonu bir kez çağrıldıktan sonra çıkılacaktır, |
| 69 | +çünkü `subLoop` `i` değişkeninin dış kapsamdaki değerini değiştirir. İkinci |
| 70 | +`for` döngüsünde de `var` kullanılması bu hatayı kolayca engelleyecektir. |
| 71 | +*Bilinçli olarak* dış kapsama erişilmek istenmiyorsa `var` ifadesi **asla** |
| 72 | +atlanmamalıdır. |
| 73 | + |
| 74 | +### Lokal değişkenler |
| 75 | + |
| 76 | +JavaScript'te lokal değişkenler sadece [fonksiyon](#function.general) |
| 77 | +parametreleri ve `var` ifadesi ile tanımlanan değişkenlerdir. |
| 78 | + |
| 79 | + // genel kapsam |
| 80 | + var foo = 1; |
| 81 | + var bar = 2; |
| 82 | + var i = 2; |
| 83 | + |
| 84 | + function test(i) { |
| 85 | + // test fonksiyonunun lokal kapsamı |
| 86 | + i = 5; |
| 87 | + |
| 88 | + var foo = 3; |
| 89 | + bar = 4; |
| 90 | + } |
| 91 | + test(10); |
| 92 | + |
| 93 | +`test` fonksiyonun içinde `foo` ve `i` lokal değişkenlerdir, `bar` değişkenine |
| 94 | +değer atanması ise genel kapsamdaki aynı isimdeki değişkenin değerini |
| 95 | +değiştirecektir. |
| 96 | + |
| 97 | +### Yukarı taşıma |
| 98 | + |
| 99 | +JavaScript'te tanımlamalar **yukarı taşınır**. Yani hem `var` ifadesi hem de |
| 100 | +`function` bildirimleri içindeki bulundukları kapsamın en üstüne taşınırlar. |
| 101 | + |
| 102 | + bar(); |
| 103 | + var bar = function() {}; |
| 104 | + var someValue = 42; |
| 105 | + |
| 106 | + test(); |
| 107 | + function test(data) { |
| 108 | + if (false) { |
| 109 | + goo = 1; |
| 110 | + |
| 111 | + } else { |
| 112 | + var goo = 2; |
| 113 | + } |
| 114 | + for(var i = 0; i < 100; i++) { |
| 115 | + var e = data[i]; |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | +Program çalışmadan önce yukarıdaki kod dönüştürülür. JavaScript, `var` |
| 120 | +ifadelerini ve `function` bildirimlerini içinde bulundukları kapsamın en üstüne |
| 121 | +taşır. |
| 122 | + |
| 123 | + // var ifadeleri buraya taşınır |
| 124 | + var bar, someValue; // varsayılan olarak 'undefined' değerini alırlar |
| 125 | + |
| 126 | + // function bildirimi de yukarı taşınır |
| 127 | + function test(data) { |
| 128 | + var goo, i, e; // blok kapsamı olmadığı için buraya taşınır |
| 129 | + if (false) { |
| 130 | + goo = 1; |
| 131 | + |
| 132 | + } else { |
| 133 | + goo = 2; |
| 134 | + } |
| 135 | + for(i = 0; i < 100; i++) { |
| 136 | + e = data[i]; |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + bar(); // bir TypeError hatası oluşur çünkü bar hala 'undefined' |
| 141 | + someValue = 42; // değer atamaları etkilenmez |
| 142 | + bar = function() {}; |
| 143 | + |
| 144 | + test(); |
| 145 | + |
| 146 | +Blok kapsamının bulunmaması nedeniyle hem `var` ifadeleri döngülerin dışına |
| 147 | +taşınır hem de bazı `if` ifadeleri anlaşılmaz sonuçlar verebilir. |
| 148 | + |
| 149 | +Orijinal programda `if` ifadesi `goo` isimli *genel değişkeni* değiştiriyor gibi |
| 150 | +görünüyordu, fakat yukarı taşımadan sonra anlaşıldığı gini aslında |
| 151 | +*lokal değişkeni* değiştiriyor. |
| 152 | + |
| 153 | +*Yukarı taşıma* dikkate alınmadığında aşağıdaki programın bir `ReferenceError` |
| 154 | +oluşturacağı sanılabilir. |
| 155 | + |
| 156 | + // SomeImportantThing değişkenine değer atanmış mı, kontrol et |
| 157 | + if (!SomeImportantThing) { |
| 158 | + var SomeImportantThing = {}; |
| 159 | + } |
| 160 | + |
| 161 | +Fakat `var` değişkeni *genel kapsamın* en üstüne taşınacağı için bu program |
| 162 | +çalışacaktır. |
| 163 | + |
| 164 | + var SomeImportantThing; |
| 165 | + |
| 166 | + // SomeImportantThing arada bir yerde atanmış olabilir |
| 167 | + |
| 168 | + // Değer atandığından emin ol |
| 169 | + if (!SomeImportantThing) { |
| 170 | + SomeImportantThing = {}; |
| 171 | + } |
| 172 | + |
| 173 | +### İsim çözümleme |
| 174 | + |
| 175 | +JavaScript'te *genel kapsam* da dahil tüm kapsamlarda [`this`](#function.this) |
| 176 | +adında bir özel değişken tanımlanmıştır, bu değişken *geçerli nesneyi* gösterir. |
| 177 | + |
| 178 | +Fonksiyon kapsamlarında aynı zamanda [`arguments`](#function.arguments) adında |
| 179 | +bir değişken tanımlanmıştır ve fonksiyonun argümanlarını içerir. |
| 180 | + |
| 181 | +Örnek olarak bir fonksiyon kapsamında `foo` değişkenine eriğildiğinde JavaScript |
| 182 | +isim çözümlemeyi aşağıdaki sıra ile yapacaktır: |
| 183 | + |
| 184 | + 1. Geçerli kapsamda bir `var foo` ifadesi mevcutsa bu kullanılır. |
| 185 | + 2. Fonksiyonun parametrelerinden birinin adı `foo` ise bu kullanılır. |
| 186 | + 3. Fonksiyonun kendisinin adı `foo` ise bu kullanılır. |
| 187 | + 4. Bir dıştaki kapsama geçilir ve yeniden **1** adımına dönülür. |
| 188 | + |
| 189 | +> **Not:** `arguments` adında bir parametre bulunması durumunda varsayılan |
| 190 | +> `arguments` nesnesi **oluşturulmayacaktır**. |
| 191 | +
|
| 192 | +### İsim uzayları |
| 193 | + |
| 194 | +Tek bir genel isim uzayının bulunmasının yol açtığı yaygın sonuç isim |
| 195 | +çakışmasıdır. JavaScript'te bu sorun *isimsiz fonksiyonlar* ile kolayca |
| 196 | +önlenebilir. |
| 197 | + |
| 198 | + (function() { |
| 199 | + // bir "isim uzayı" |
| 200 | + |
| 201 | + window.foo = function() { |
| 202 | + // korunmasız bir closure |
| 203 | + }; |
| 204 | + |
| 205 | + })(); // fonksiyonu hemen çalıştır |
| 206 | + |
| 207 | +İsim siz fonksiyonlar [ifade](#function.general) olarak değerlendirilir; |
| 208 | +bu nedenle çağrılabilmeleri için önce değerlendirilmeleri gerekir. |
| 209 | + |
| 210 | + ( // parantezin içindeki fonksiyonu değerlendir |
| 211 | + function() {} |
| 212 | + ) // ve fonksiyon nesnesini döndür |
| 213 | + () // değerlendirmenin sonucu fonksiyon nesnesini çağır |
| 214 | + |
| 215 | +Bir fonksiyon ifadesini değerlendirip çağırmanın başka yolları da vadır ve |
| 216 | +yukarıdaki ile aynı sonucu verirler. |
| 217 | + |
| 218 | + // İki farklı yöntem |
| 219 | + +function(){}(); |
| 220 | + (function(){}()); |
| 221 | + |
| 222 | +### Sonuç |
| 223 | + |
| 224 | +Programı kendi isim uzayı ile kapsamak için her zaman *isimsiz fonksiyonların* |
| 225 | +kullanılması tavsiye olunur. Böylece hem isim çakışmalarından korunulmuş olunur, |
| 226 | +hem de programlar daha modüler halde yazılmış olur. |
| 227 | + |
| 228 | +Ayrıca, genel değişkenlerin kullanılması **kötü bir uygulamadır**. Genel |
| 229 | +değişkenlerin *herhangi bir şekilde* kullanılmış olması programın kötü yazılmış |
| 230 | +olduğuna, hatalara eğilimli olduğuna ve sürdürülmesinin zor olacağına işaret |
| 231 | +eder. |
| 232 | + |
0 commit comments