Var, Let, Const
ES2015 (ES6)'ten sonra Javascript dünyasında bir çok şey değişti. Değişkenleri tanımlama şekillerine artık 2020 olduğuna göre çoktan adapte olmuş olmamız gerekiyor. Bu yazımı hala kafasında karışıklıklar olanlar , yeni öğrenmeye başlayanlar için ve bir de not olsun diye yazıyorum.
Asıl mevzuya girmeden önce, bilmemiz gereken iki önemli kavram var: scope ve closure.
Javascript dilinin en havalı özelliklerinden biridir closure. Her hangi bir fonksiyon tanımladığımızda bir closure oluşur ve o fonksiyonun hangi scope'taki verilere erişebileceği belirlenir.
Scope
İki adet süslü parantez { arasına } sıkıştırılan objeler dünyası diyebiliriz. Üç türlüdür: global , function ve block scope.
Scope, fonksiyon içerisindeki değişkenlerin erişebilirliğini belirler. Bir fonksiyon içerisinde tanımlanan değişken (variable), fonksiyon dışında erişilemez.
function saySomething() {
let name = "Emre";
console.log(`Hello ${name}`); // Hello Emre
}
console.log(`Hello ${name}`); // Refference error: name is not defined
Ancak ve ancak, kendi scope içerisinden ya da global scope görevi gördüğü nested fonksiyonlar içerisinden erişilebilir.
function saySomething() {
let name = "Emre";
console.log(`Hello ${name}`); // Hello Emre
function saySomethingElse(x) {
console.log(`How are you ${name}?`); // How are you Emre?
if(x) {
let y = x + 1;
console.log(y);
}
}
}
console.log(`Hello ${name}`); // Refference error: name is not defined
Fonksiyonlar gibi if, for, while, switch case yapıları da kendi block scope'larına sahiptir. Yukarıdaki örnekteki gibi if de kendi scope'una sahip ve içerisindeki değişkenlere üst katman scopelardan erişilemez.
Closure
Diğer bir şekilde ifade etmek gerekirse, bir fonksiyonun erişebileceği scope listesidir.
Yukarıdaki örneği düşünürsek, saySomething fonksiyonu global değişkenlere ve kendi içerisinde tanımlanan değişkenlere erişebilir.
let surname = "Demir";
function saySomething() {
let name = "Emre";
console.log(`Hello ${name} ${surname}`); // Hello Emre Demir
function saySomethingElse() {
console.log(`How are you ${name} ${surname}?`);
// How are you Emre Demir?
}
}
console.log(`Hello ${name}`); // Refference error: name is not defined
saySomething için closure : [global scope, kendi scope'u]
saySomethingElse için closure: [global scope, saySomething scope'u, kendi scope'u].
Var
ES6'den önce ve hala kullanılabilen değişken tanımlama yöntemi. Eğer bir fonksiyon dışında tanımlanıyorsa global scoped, içerisinde tanımlanıyorsa function scoped olarak geçer.
var greeting = "Hey, hi";
function newFunction() {
var hello = "hello";
}
console.log(hello); // reference error: hello is not defined
Tekrar tekrar tanımlanabilir ya da yeni değer ataması yapılabilirler.
var greeting = "Hey, hi";
var greeting = "Hey, helloooo";
greeting = "Whats up?";
console.log(greeting); // Whats up?
Bir diğer ilginç özelliği ise, scope unun en üstünde konumlanır ve ilk değer olarak undefined atanır. Aşağıdaki ilk örnek, ikinci örnekteki gibi yorumlanır. Yani reference error almazsınız ama ilk değeri undefined idir.
console.log(greeting); // greeting is undefined
greeting = "Whats up?";
var greeting;
console.log(greeting);
greeting = "Whats up?";
Peki var ile ilgili problem ne?
Belki de okurken çoktan farkettiniz bile. var ile tanımlanan değişkenler tekrar ve tekrar tanımlanabilir ve atama yapılabilir.
var greeting = "Hey hello";
var firstMet = true;
if (firstMet) {
var greeting = "Nice to meet you!";
}
console.log(greeting); // "Nice to meet you!"
Görüldüğü gibi kodun akışı gereği, greeting değişkeni tekrar if bloğu içerisinde tanımlandı ve atama yapıldı. İsteyerek yapıldığı sürece sıkıntı yok ama gerçek projelerimizde binlerce satır kod yazdığımız için, bazen bilmeyerek aynı değişken ismini birden fazla yerde kullanıyoruz ve bir yerlerde beklenmedik çıktılar alabiliyoruz.
Let
ES6 ile beraber gelen yeni değişken tanımlama yöntemi, var ile karşılaştığımız sorunu çözdü. Block scoped bir tanımlama şekli olan let ile oluşturulan değişkenler, tekrar atama yapılabilir ama tanımlanamaz.
let greeting = "say Hi";
let greeting = "say Hello"; // error: Identifier 'greeting' has already been declared
let greeting = "Hey hello";
let firstMet = true;
if (firstMet) {
let greeting = "Nice to meet you!";
}
console.log(greeting); // "Hey hello"
Gördüğünüz gibi let daha güvenli bir tanımlama şekli ve yukarıda bir yerde tekrar aynı değişkeni kullandım mı acaba endişesinden kurtulmanızı sağlıyor.
Const
Sabit değişkenlerimizi tanımladığımız const da aynı let gibi block scoped idir. Sadece kendi bloğu/scope u içerisinde erişilebilir. Ancak tekrar atama ve tanımlama yapılamaz. Tanımlandığında değeri verilmelidir.
const greeting = "Hey hello";
greeting = "Nice to meet you!";// error: Assignment to constant variable.
const greeting = "Hey hello";
const greeting = "Nice to meet you!";
// error: Identifier 'greeting' has already been declared
Ancak object olarak tanımlarsak, değerlerini değiştirebiliriz. Ama yine de yeni atama yapamayız.
const greeting = {
message: "Hey hello",
firstMet: false
};
greeting.firstMet = true;
greeting.message = "Nice to meet you!";
const greeting = {
message: "Hey hello",
firstMet: false
};
greeting = {
message: "Nice to meet you!",
firstMet: true
}; // error: Assignment to constant variable.
Bu yazı da bir not niteliğinde burada bulunsun istedim. Eğer sorularınız ya da yanlış bilgilendirdiğimi düşündüğünüz noktalar varsa belirtirseniz sevinirim.
Kodla, umutla ve güvende kalınız...