Coding / Programming Videos

Post your favorite coding videos and share them with others!

Javascript’te Scope kavramını anlamak – Yusuf GÜNGÖR – Medium

Source link

Javascriptin Scope denilen bir özelliği vardır. Böyle bir konsept olmasına rağmen yeni geliştiriciler için bunu anlamak kolay değildir. Bunu basit şekilde size anlatmaya çalışacağım. Scope kavramını anlamak kodunuzu ön plana çıkarır, hataları azaltır ve daha güçlü bir tasarım deseni oluşturmanıza yardımcı olur.

Konu başlıkları

  • Scope nedir?
  • Neden Scope? En az erişim prensibi
  • JavaScript’te Scope
  • Global Scope
  • Yerel (Local) Scope
  • Blok ifadeleri (Block Statements)
  • Context (Bağlam)
  • Yürütme Bağlamı (Execution Context)
  • Lexical Scope
  • Closures
  • Public and Private Scope
  • Changing Context with .call(), .apply() and .bind()
  • Conclusion

Scope nedir?

Scope, çalışma zamanı sırasında kodunuzun belirli bir bölümündeki değişkenlerin, fonksiyonların ve nesnelerin(objects) erişilebilirliğidir. Başka bir deyişle, Scope, kodunuzun belli kısımlarında değişkenlerin ve benzerlerinin görünürlüğüdür.

Neden Scope? En az erişim prensibi

Değişkenlerin görünürlüğünü sınırlandırmanın ve her yerde erişememenin amacı nedir? Çünkü bu işlem bize bir miktar güvenlik sağlar ve bu da bir avantajdır.

Bilgisayar yöneticilerini düşünün. Şirketin sistemleri üzerinde çok fazla kontrole sahip oldukları için, onlara tam erişim kullanıcı hesabı vermek uygun görünebilir. Hepsi sistemlere tam erişime sahip üç yöneticili bir şirketiniz olduğunu ve her şeyin sorunsuz çalıştığını varsayalım. Fakat aniden kötü bir şey oldu ve sisteminizden birine kötü amaçlı bir virüs bulaştı. Şimdi kimin hatası olduğunu bilmiyor musun? Bu yüzden herkese tam erişim vermemelisiniz. Bu, değişiklikleri izlemenize ve kimin ne yaptığını açıklamanıza yardımcı olur. Buna En Az Erişim Prensibi denir. Bu ilke, programlama dili tasarımlarına da uygulanır. Bu ilke, daha sonra çalışacağımız JavaScript dahil olmak üzere çoğu programlama dilinde Scope olarak adlandırılan programlama dili tasarımlarına da uygulanır.

Programlama yolculuğunuza devam ederken, Scope kullanımının kodunuzun verimliliği artırmaya, hatalarınızı izlemeye ve azaltmanıza yardımcı olduğunu fark edeceksiniz. Scope, aynı ada sahip, ancak farklı kapsamlarda değişkenleriniz olduğunda adlandırma sorununuzu da çözer.

JavaScript’te Scope

Javascript dilinde iki tip Scope vardır:

Değişken bir fonksiyonun içinde tanımlanırsa Local Scope olur eğer fonksiyonun dışında tanımlanırsa Global Scope olur. Tüm fonksiyonlar kendi içinde yeni bir Scope oluşturur.

Global Scope

Bir dosyaya JavaScript kodu yazmaya başladığınızda Global kapsamdasınız demektir. Bir JavaScript dosyasında yalnızca bir Global Scope vardır.

// burada Scope ön tanımlı olarak Globaldir
var isim = 'Yusuf'

Global kapsam içindeki değişkenlere başka bir kapsamda erişilebilir ve değiştirilebilir.

var isim = 'Yusuf';
console.log(isim); // 'Yusuf'
function isimYazdir() {
console.log(isim);
// 'isim' değişkenine buradan ve heryerden erişilebilir
}
isimYazdir(); // 'Yusuf'

Local Scope

Değişken bir fonksiyonun içinde tanımlanmışsa o değişken Local Scope’a sahiptir. Bu şu anlama gelmektedir biz her farklı Scope’da aynı isimle değişkenler tanımlayabiliriz ve birbirlerine karışmazlar. Çünkü onlar bulunduğu Scope’un değişkenidirler ve başka bir Scope’a sahip fonksiyondan erişilemezler.

// Global Scope
function birFonksiyon() {
// Local Scope #1
function baskaBirFonksiyon() {
// Local Scope #2
}
}
// Global Scope
function digerFonksiyon() {
// Local Scope #3
}
// Global Scope

Blok ifadeleri (Block Statements)

if ve switch gibi koşullu ifadeler veya for ve while gibi döngü ifadeleri fonksiyonların yaptığı gibi Scope oluşturmazlar. Burada tanımlanan değişkenler yine bulundukları Scope’a bağlı olacaklardır.

if (true) {
// bu ifade yeni bir scope oluşturmaz
var isim = 'Yusuf'; // isim değişkeni hala Global Scope
}
console.log(isim); // 'Yusuf'

ECMAScript 6 ile let ve const anahtar kelimeleri tanıtıldı. Bu anahtar kelimeler var anahtar kelimesinin yerine kullanılabilir.

var isim = 'Yusuf';
let kod = 'kodluyorum';
const yetenekler = 'Javascript and Java';

Var anahtar sözcüğünün aksine, let ve const anahtar sözcükleri if ve for gibi blok ifadelerinin içinde kendi kendine Scope oluştururlar.

if (true) {
// if ifadesi kendi başına Scope oluşturmaz
// isim değişkeni Global Scope'a sahiptir çünkü var anahtar kelimesi ile tanımlanmış
var isim = 'Yusuf';
 // begeniler değişkeni Local Scope'a sahiptir çünkü let anahtar kelimesi ile tanımlanmış
let begeniler = 'Kodlamak';
// yetenekler değişkeni Local Scope'a sahiptir çünkü const anahtar kelimesi ile tanımlanmış
const yetenekler = 'JavaScript and PHP';
}
console.log(isim); // 'Yusuf'
console.log(begeniler); // begeniler tanımlanmamış
console.log(yetenekler); // yetenekler tanımlanmamış

Global Scope, uygulamanız devam ettiği sürece yaşar. Local Scope, işlevleriniz çağrılıp yürütüldüğü sürece yaşar.

Context (Bağlam)

Birçok geliştirici, genellikle Scope ve Context kavramlarının aynı şeyi ifade ettiğini düşünerek bu ikisini karıştırır. Ama aynı şey değildirler. Scope yazının yukarısında anlamaya çalıştığımız şeydir ve Context ise , kodunuzun belirli bir bölümündeki this değerini ifade etmek için kullanılır. Eğer bir nesnenin içinde değilseniz this kavramı yine window nesnesini işaret edecektir.

// ekran çıktısı: Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage…}
console.log(this);
function ekranaYaz() {
console.log(this);
}
// ekran çıktısı: Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage…}
// çünkü ekranaYaz() bir nesnenin özelliği değil
ekranaYaz();

Eğer bir nesnenin içindeyseniz this kavramı bu sefer o nesneyi işaret edecektir.

class Kullanici {
yazdir() {
console.log(this);
}
}
var yeniKullanici = new Kullanici;
yeniKullanici.yazdir(); // ekran çıktısı: Kullanici {}

Eğer bir fonksiyonu new anahtar kelimesi ile çağırırsanız nesne gibi davranacaktır ve bu sefer this kavramı o fonksiyonu ifade edecektir.

function ekranaYazdir() {
console.log(this);
}
new ekranaYazdir(); // ekran çıktısı: ekranaYazdir {}

Lexical Scope (Sözcüksel Kapsam)

Lexical Scope, iç içe geçmiş bir işlev grubunda, iç işlevlerin değişkenlere ve kendi ana kapsamlarındaki diğer kaynaklara erişebileceği anlamına gelir. Bu, içte bulunan fonksiyonların üstte bulunan fonksiyonların yürütme bağlamına sözcüksel olarak bağlı olduğu anlamına gelir. Lexical Scope bazen Static Scope olarak da adlandırılır.

function dede() {
var isim = 'Yusuf';
// hobi değişkenine erişilemez
function baba() {
// isim değişkenine erişilebilir
// hobi değişkenine erişilemez
function cocuk() {
// isim değişkenine buradan da erişilebilir
var hobi = 'kodlamak';
}
}
}

Gördüğümüz gibi en içteki fonksiyon içinde bulunduğu diğer fonksiyonların varlıklarına erişebilir ancak bu yöntem en dıştan en içe çalışmaz.

The Module Pattern (Modül Deseni)

Modül deseni ise şöyledir:

var Modul = (function() {
function gizliFonksiyon() {
// birşey yap
}
return {
herkeseAcikFonksiyon: function() {
// gizliFonksiyon() çağır;
}
};
})();

Modülün return ifadesi bizim gizli fonksiyonlarımızı içerir. Özel fonksiyonlar sadece direkt çağırılamayan fonksiyonlardır. Modül deseni sayesinde bu fonksiyonlar erişilemez hale gelir.

Module.herkeseAcikFonksiyon(); // çalışır
Module.gizliFonksiyon(); // Ekran çıktısı Uncaught ReferenceError: gizliFonksiyon is not defined

Genel olarak gizli fonksiyonlar isimlendirilirken “_” ile başlanır bu kod bloğumuz büyüdüğünde bize ayırt etmede yardımcı olur.

var Modul = (function () {
function _gizliFonksiyon() {
// birşey yap
}
function herkeseAcikFonksiyon() {
// birşey yap
}
return {
herkeseAcikFonksiyon: herkeseAcikFonksiyon,
}
})();

Bağlam Değiştirme (Changing Context) with .call(), .apply() and .bind()

call() ve apply() işlevleri, bir işlevi çağırırken contexti (bağlamı) değiştirmek için kullanılır. Call veya apply işlevini kullanmak için, işlevi bir parantez kullanarak çağırmak yerine işlev üzerinde çağırmanız ve context’i ilk argüman olarak iletmeniz yeterlidir. Örneklerle inceleyelim.

function selam() {
// birşeyler yap
}
selam(); // genelde böyle çağrılıt
selam.call(context);
selam.apply(context);

.Call () ve .apply () arasındaki fark, Call’da, argümanların geri kalanını virgülle ayrılmış bir liste olarak iletebilmenizdir.

function kendiniTanit(isim, ilgiAlani) {
console.log('Merhaba! Ben '+ isim +' ve '+ ilgiAlani +' severim.');
console.log('This: '+ this +'.')
}
kendiniTanit('Yusuf', 'kodlamayı'); // genel kullanım
kendiniTanit.call(window, 'Ahmet', 'gezmeyi'); // diğer parametreleri ',' ile ayırarak gönderebiliriz
kendiniTanit.apply('selam', ['Mehmet', 'işimi']); // diğer parametreleri array ile gönderebiliriz
// Ekran çıktıları:
// Merhaba! Ben Yusuf ve kodlamayı severim.
// This: [object Window].
// Merhaba! Ben Ahmet ve gezmeyi severim.
// This: [object Window].
// Merhaba! Ben Mehmet işimi severim.
// This: selam.

Şimdiye kadar .call (), .apply ()‘i tartıştık. Call ve apply’dan farklı olarak, Bind işlevi kendisi çağırmaz, işlevi çağırmadan önce yalnızca context ve diğer argümanların değerini bağlamak için kullanılabilir. Bind uygulamasını yukarıdaki örneklerden birinde kullanalım:

(function kendiniTanit(isim, ilgiAlani) {
console.log('Merhaba! Ben '+ isim +' ve '+ ilgiAlani +' severim.');
console.log('This '+ this +'.')
}).bind(window, 'Yusuf', 'kodlamayı')();
// Ekran Çıktısı:
// Merhaba! Ben Yusuf ve kodlamayı severim.
// This: [object Window].

Bind, call işlevi gibi aynı şekilde kullanılır.

Orjinal yazının tamamını çeviremedim bu kadarıyla umarım faydalı olmuştur. Gördüğünüz eksikleri belirtirseniz hemen düzeltebilirim. İyi çalışmalar.. 🙂

Source link

Bookmark(0)
 

Leave a Reply

Please Login to comment
  Subscribe  
Notify of
Translate »