Çerezler
Bu web sitesi sizlere daha iyi hizmet verebilmek için çerezleri kullanır.
                            Web sayfaları, tarayıcılar tarafından yüklenirken bir Belge Nesne Modeli (DOM) olarak yapılandırılır. Bu model, HTML belgesinin mantıksal yapısını temsil eder ve JavaScript'in web sayfasının içeriğine, yapısına ve stiline dinamik olarak erişmesini ve bunları değiştirmesini sağlayan bir API (Uygulama Programlama Arayüzü) sunar. Bu makale, JavaScript kullanarak HTML DOM ile nasıl etkileşim kuracağınızı, elementleri nasıl seçeceğinizi, içeriklerini ve stillerini nasıl değiştireceğinizi ve olayları nasıl yöneteceğinizi adım adım açıklayacaktır.
JavaScript'in DOM ile etkileşim kurmasının temelinde, belgedeki HTML elementlerini seçmek ve ardından bu elementlerin özelliklerine veya metotlarına erişmek yatar. Aşağıdaki sözdizimleri, en yaygın DOM seçim ve manipülasyon yöntemlerini özetlemektedir:
// Element seçimi
document.getElementById("elementId");
document.getElementsByClassName("className");
document.getElementsByTagName("tagName");
document.querySelector("cssSelector");
document.querySelectorAll("cssSelector");
// Element özellikleri ve metotları
element.innerHTML;
element.textContent;
element.style.propertyName;
element.setAttribute("attributeName", "value");
element.classList.add("className");
element.addEventListener("eventName", functionHandler);
document.createElement("tagName");
parentElement.appendChild(childElement);
parentElement.removeChild(childElement);document Nesnesi: DOM'a erişimin ana giriş noktasıdır. Tüm HTML belgesini temsil eder.
Element Seçim Metotları:
document.getElementById("elementId"): Belirtilen id niteliğine sahip tek bir elementi döndürür. id'ler bir sayfada benzersiz olmalıdır.
document.getElementsByClassName("className"): Belirtilen sınıf adına sahip tüm elementleri içeren bir HTMLCollection döndürür. Canlı bir koleksiyondur, yani DOM'daki değişiklikler koleksiyonu otomatik olarak günceller.
document.getElementsByTagName("tagName"): Belirtilen etiket adına sahip tüm elementleri içeren bir HTMLCollection döndürür.
document.querySelector("cssSelector"): Belirtilen CSS seçici ile eşleşen belgedeki ilk elementi döndürür.
document.querySelectorAll("cssSelector"): Belirtilen CSS seçici ile eşleşen tüm elementleri içeren bir NodeList döndürür. Statik bir koleksiyondur.
Element Özellikleri ve Metotları:
element.innerHTML: Bir elementin HTML içeriğini (alt elementler dahil) alır veya ayarlar. HTML etiketlerini yorumlar.
element.textContent: Bir elementin ve tüm alt elementlerinin metin içeriğini alır veya ayarlar. HTML etiketlerini metin olarak ele alır.
element.style.propertyName: Bir elementin CSS stil özelliklerine erişim sağlar. Örneğin, element.style.backgroundColor = "red";.
element.setAttribute("attributeName", "value"): Bir elementin belirtilen niteliğini ayarlar veya günceller. Örneğin, element.setAttribute("href", "https://example.com");.
element.classList: Bir elementin CSS sınıflarını yönetmek için bir dizi metot (add, remove, toggle, contains) sunar.
element.addEventListener("eventName", functionHandler): Bir elemente olay dinleyicisi ekler. Örneğin, bir butona tıklama olayını dinlemek için "click" kullanılır.
document.createElement("tagName"): Belirtilen etiket adıyla yeni bir HTML elementi oluşturur.
parentElement.appendChild(childElement): Belirtilen bir çocuğu, belirtilen ana elementin son çocuğu olarak ekler.
parentElement.removeChild(childElement): Belirtilen ana elementten belirtilen çocuğu kaldırır.
Aşağıdaki örnekler, JavaScript'in DOM ile nasıl etkileşim kurduğunu göstermektedir.
Örnek 1: Bir HTML Elementinin İçeriğini Güncelleme
Bu örnekte, bir paragraf elementinin metin içeriği JavaScript ile değiştirilmektedir.
Merhaba Dünya!
Örnek 2: Bir Elementin Stilini Değiştirme
Bu örnek, bir  Örnek 3: Yeni Bir Element Oluşturma ve Ekleme Bu örnek, dinamik olarak yeni bir liste öğesi oluşturup mevcut bir listeye ekler. Örnek 4: Bir Olay Dinleyicisi Ekleme Bu örnek, bir butona tıklanma olayını dinler ve tıklandığında bir paragrafın içeriğini günceller. Henüz tıklanmadı. Betik Yerleşimi ve Yükleme: JavaScript kodunuzun HTML DOM elementlerine erişmeye çalışmadan önce, bu elementlerin tarayıcı tarafından yüklenmiş ve DOM'a eklenmiş olması gerekir. Bu genellikle  Performans İpuçları: Kapsamlı DOM manipülasyonları performans maliyetli olabilir. Büyük değişiklikler yaparken, elementleri DOM'dan kaldırın, değişiklikleri yapın ve sonra tekrar ekleyin. Ayrıca, birden fazla stil değişikliği için  Güvenlik (XSS): Kullanıcı girdilerini 
    
Önemli Notlar
    
                                 etiketini  etiketinin kapanışından hemen önce yerleştirerek veya defer/async niteliklerini kullanarak sağlanır. Alternatif olarak, document.addEventListener("DOMContentLoaded", function() { /* kodunuz */ }); kullanarak kodunuzun DOM tamamen yüklendikten sonra çalışmasını sağlayabilirsiniz.id Benzersizliği: document.getElementById() metodu için kullanılan id nitelikleri, HTML belgesi içinde benzersiz olmalıdır. Aynı id'ye sahip birden fazla element bulunması durumunda, metot yalnızca ilk eşleşeni döndürecektir.HTMLCollection ve NodeList: getElementsByClassName ve getElementsByTagName metotları HTMLCollection, querySelectorAll ise NodeList döndürür. Bu koleksiyonlar dizi benzeri nesnelerdir ancak tüm dizi metotlarına (map, filter vb.) doğrudan sahip değildirler. Üzerlerinde döngü kurmak için for...of veya Array.from().forEach() kullanabilirsiniz.element.style.cssText özelliğini kullanabilir veya CSS sınıflarını (classList) manipüle edebilirsiniz.innerHTML ile doğrudan DOM'a eklerken dikkatli olun. Kötü niyetli kullanıcılar, bu yöntemle sitenize Cross-Site Scripting (XSS) saldırıları yapabilirler. Güvenliğiniz için genellikle textContent kullanmak veya girdileri sanitize etmek daha iyidir.null Kontrolü: DOM elementlerini seçerken, bazen elementin sayfada var olmayabileceği durumlar olabilir. Bu tür durumlarda, döndürülen değer null olacaktır. Kodunuzun beklenmedik hatalar vermesini önlemek için element üzerinde işlem yapmadan önce bir null kontrolü yapmak iyi bir pratiktir (örneğin, if (element) { ... }).
                            JavaScript, doğası gereği tek iş parçacıklı (single-threaded) bir dildir. Bu durum, uzun süren veya dış kaynaklara bağımlı işlemleri (örneğin, ağ istekleri, dosya okuma/yazma) doğrudan ana iş parçacığında yürütmenin kullanıcı arayüzünü kilitlemesine ve uygulamanın donmasına neden olacağı anlamına gelir. Bu tür senaryolarda uygulamanın yanıt verebilirliğini korumak ve verimli çalışmasını sağlamak için asenkron programlama teknikleri kullanılır. Bu kılavuz, JavaScript'te asenkron işlemlerin nasıl yönetildiğini, özellikle modern async/await sözdizimi ve altında yatan Promise mekanizmasını adım adım açıklamaktadır.
Modern JavaScript'te asenkron kod yazmanın en yaygın ve okunabilir yolu async ve await anahtar kelimelerini kullanmaktır. Bu sözdizimi, Promise tabanlı asenkron kodun senkron koda benzer bir şekilde yazılmasını sağlar.
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Veri çekme hatası:', error);
  }
}
fetchData();
async Anahtar Kelimesi:
    Bir fonksiyonun önüne async anahtar kelimesini eklemek, o fonksiyonu her zaman bir Promise döndüren asenkron bir fonksiyon yapar. Eğer fonksiyon açıkça bir Promise döndürmüyorsa, JavaScript otomatik olarak döndürülen değeri bir Promise içine sarar. Bu, asenkron fonksiyonların zincirleme (chaining) bir şekilde veya await ile kullanılabilmesini sağlar.
await Anahtar Kelimesi:
    Sadece async olarak işaretlenmiş bir fonksiyonun içinde kullanılabilen await anahtar kelimesi, bir Promise'in çözülmesini (yani başarılı bir şekilde tamamlanmasını veya reddedilmesini) bekler. await kullanılan satırda kodun yürütülmesi duraklatılır ve Promise çözüldüğünde devam eder. Eğer Promise başarılı olursa, await ifadesi Promise'in değerini döndürür. Eğer Promise reddedilirse, await bir hata fırlatır ve bu hata try...catch bloğu ile yakalanabilir.
Promise Nesnesi:
    async/await sözdiziminin temelinde Promise nesnesi yatar. Bir Promise, asenkron bir işlemin nihai sonucunu (başarı değeri veya hata nedeni) temsil eden bir JavaScript nesnesidir. Üç ana durumu vardır:
    
pending (beklemede): Asenkron işlem henüz tamamlanmadı.
fulfilled (tamamlandı/çözüldü): Asenkron işlem başarıyla tamamlandı ve bir değer döndürdü.
rejected (reddedildi): Asenkron işlem bir hata nedeniyle başarısız oldu.
Promise'ler, .then() metodu ile başarılı sonuçları, .catch() metodu ile hataları ve .finally() metodu ile her iki durumda da çalışacak kod bloklarını yönetmek için kullanılır.
  Bu örnek, bir ağ isteğini simüle eden bir fonksiyonun async/await ile nasıl çağrıldığını ve sonucunun nasıl işlendiğini göstermektedir.
function simulateNetworkRequest(url) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`Veri ${url} adresinden başarıyla çekildi.`);
      resolve({ id: 1, data: `Veri ${url} için` });
    }, 2000); // 2 saniye gecikme
  });
}
async function getDataFromApi() {
  console.log('API\'den veri çekiliyor...');
  const result = await simulateNetworkRequest('https://api.example.com/users');
  console.log('Çekilen veri:', result);
  console.log('Veri çekme işlemi tamamlandı.');
}
getDataFromApi();
// Beklenen Çıktı:
// API'den veri çekiliyor...
// (2 saniye sonra)
// Veri https://api.example.com/users adresinden başarıyla çekildi.
// Çekilen veri: { id: 1, data: 'Veri https://api.example.com/users için' }
// Veri çekme işlemi tamamlandı.
Asenkron işlemlerde hata yönetimi kritik öneme sahiptir. try...catch blokları, await ile tetiklenen Promise reddedilmelerini yakalamak için kullanılır.
function simulateFailedNetworkRequest(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() > 0.5) { // Rastgele hata simülasyonu
        reject(new Error(`Hata: ${url} adresinden veri çekilemedi.`));
      } else {
        resolve({ id: 2, data: `Başarılı veri ${url} için` });
      }
    }, 1500);
  });
}
async function fetchDataWithErrorHandling() {
  console.log('Hata yönetimi ile veri çekiliyor...');
  try {
    const data = await simulateFailedNetworkRequest('https://api.example.com/products');
    console.log('Çekilen veri:', data);
  } catch (error) {
    console.error('Bir hata oluştu:', error.message);
  } finally {
    console.log('Veri çekme girişimi sonlandı.');
  }
}
fetchDataWithErrorHandling();
// Beklenen Çıktı (başarılı olursa):
// Hata yönetimi ile veri çekiliyor...
// (1.5 saniye sonra)
// Çekilen veri: { id: 2, data: 'Başarılı veri https://api.example.com/products için' }
// Veri çekme girişimi sonlandı.
// Beklenen Çıktı (hata olursa):
// Hata yönetimi ile veri çekiliyor...
// (1.5 saniye sonra)
// Bir hata oluştu: Hata: https://api.example.com/products adresinden veri çekilemedi.
// Veri çekme girişimi sonlandı.
Birden fazla asenkron işlemi aynı anda başlatmak ve hepsinin tamamlanmasını beklemek için Promise.all() kullanılabilir. Bu, bekleme sürelerini optimize eder.
function fetchResource(resourceName, delay) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`${resourceName} çekildi.`);
      resolve(`${resourceName} verisi`);
    }, delay);
  });
}
async function fetchMultipleResources() {
  console.log('Kaynaklar paralel olarak çekiliyor...');
  const [users, products, orders] = await Promise.all([
    fetchResource('Kullanıcılar', 3000), // 3 saniye
    fetchResource('Ürünler', 1000),    // 1 saniye
    fetchResource('Siparişler', 2000)   // 2 saniye
  ]);
  console.log('Tüm kaynaklar çekildi.');
  console.log('Kullanıcılar:', users);
  console.log('Ürünler:', products);
  console.log('Siparişler:', orders);
}
fetchMultipleResources();
// Beklenen Çıktı:
// Kaynaklar paralel olarak çekiliyor...
// (1 saniye sonra) Ürünler çekildi.
// (2 saniye sonra) Siparişler çekildi.
// (3 saniye sonra) Kullanıcılar çekildi.
// Tüm kaynaklar çekildi.
// Kullanıcılar: Kullanıcılar verisi
// Ürünler: Ürünler verisi
// Siparişler: Siparişler verisi
await Kullanımı: await anahtar kelimesi yalnızca async olarak işaretlenmiş fonksiyonların içinde kullanılabilir. Global kapsamda veya senkron fonksiyonlarda doğrudan await kullanmaya çalışmak sözdizimi hatasına yol açacaktır.
async Fonksiyonların Dönüş Değeri: Her async fonksiyon, döndürdüğü değeri otomatik olarak bir Promise içine sarar. Eğer bir değer döndürülmezse, Promise.resolve(undefined) döndürülür.
Hata Yönetimi: async/await ile hata yönetimi için try...catch blokları kullanmak, senkron koddaki hata yönetimine benzer bir yapı sunarak kodu daha okunabilir hale getirir. Promise reddedildiğinde, await bir hata fırlatır ve bu catch bloğu tarafından yakalanır.
Promise.all() ve Paralellik: Birden fazla bağımsız asenkron işlemi paralel olarak yürütmek ve hepsinin sonucunu beklemek için Promise.all() kullanın. Bu, toplam yürütme süresini önemli ölçüde azaltabilir. Eğer işlemlerden herhangi biri reddedilirse, Promise.all() hemen reddedilerek hatayı döndürür.
Bloke Edici Olmayan (Non-blocking) Yapı: Asenkron işlemler, uzun süren görevlerin ana iş parçacığını bloke etmesini engeller. Bu sayede uygulamanız kullanıcı etkileşimlerine yanıt vermeye devam eder ve daha akıcı bir kullanıcı deneyimi sunar.
Callback Hell'den Kaçınma: async/await, iç içe geçmiş yoğun geri çağırma (callback) fonksiyonlarından kaynaklanan "callback hell" sorununu çözmek için modern ve daha temiz bir alternatif sunar. Bu, kodun okunabilirliğini ve bakımını büyük ölçüde iyileştirir.
                            JavaScript, ES6 (ECMAScript 2015) ile birlikte nesne yönelimli programlama (OOP) ilkelerini daha net ve tanıdık bir sözdizimi ile uygulamak için sınıfları (classes) tanıttı. Sınıflar, prototip tabanlı kalıtım üzerine inşa edilmiş sentaktik bir şeker (syntactic sugar) olup, nesne oluşturmak ve kalıtımı yönetmek için daha anlaşılır bir yapı sunar. Bu makale, JavaScript sınıflarının temel kullanımını, sözdizimini ve pratik uygulamalarını detaylı bir şekilde ele alacaktır.
class SınıfAdı {
  constructor(parametre1, parametre2) {
    this.özellik1 = parametre1;
    this.özellik2 = parametre2;
  }
  metotAdı(argüman) {
    // Metot içeriği
    return this.özellik1 + argüman;
  }
  get getterAdı() {
    return this.özellik1;
  }
  set setterAdı(yeniDeğer) {
    this.özellik1 = yeniDeğer;
  }
  static statikMetot() {
    return "Bu bir statik metottur.";
  }
}
JavaScript sınıfları, bir nesnenin nasıl oluşturulacağını tanımlayan bir şablon görevi görür. Temel bileşenleri şunlardır:
class Anahtar Kelimesi: Bir sınıf tanımlamak için kullanılır. Sınıf adı genellikle büyük harfle başlar (PascalCase).
constructor() Metodu: Bir sınıfın özel bir metodudur. Sınıftan yeni bir nesne (instance) oluşturulduğunda otomatik olarak çağrılır. Nesnenin başlangıç durumunu (özelliklerini) ayarlamak için kullanılır. Eğer bir sınıf için açıkça bir constructor tanımlanmazsa, JavaScript varsayılan, boş bir constructor ekler.
Özellikler (Properties): Sınıf örneklerinin sahip olduğu verilerdir. constructor içinde this.özellikAdı = değer; şeklinde tanımlanır ve her örnek için benzersiz olabilir.
Metotlar (Methods): Sınıf örneklerinin gerçekleştirebileceği eylemleri tanımlayan fonksiyonlardır. metotAdı(argümanlar) { ... } şeklinde tanımlanır ve sınıfın prototipine eklenir.
Getter ve Setter Metotları: Özelliklerin değerlerine kontrollü erişim sağlamak için kullanılırlar. Bir özelliğin değerini okumak için get, değiştirmek için set anahtar kelimeleriyle tanımlanırlar. Bunlar aslında birer fonksiyon olmasına rağmen, özellik gibi erişilirler.
Statik Metotlar (Static Methods): Bir sınıfın kendisine ait olan, ancak sınıfın örneklerine ait olmayan metotlardır. Bu metotlar, sınıfın adıyla doğrudan çağrılır ve genellikle sınıfın örneklerine özgü olmayan yardımcı fonksiyonlar veya fabrika metotları için kullanılır. static anahtar kelimesiyle tanımlanır.
Örnek 1: Temel Sınıf Tanımlama ve Kullanımı
Aşağıdaki örnek, bir Kişi sınıfının nasıl tanımlandığını ve bu sınıftan nasıl nesneler oluşturulduğunu göstermektedir. Ayrıca sınıfın metotlarının nasıl çağrıldığını da içerir.
class Kişi {
  constructor(ad, soyad, yaş) {
    this.ad = ad;
    this.soyad = soyad;
    this.yaş = yaş;
  }
  tamAdGetir() {
    return `${this.ad} ${this.soyad}`;
  }
  yaşınıArtır() {
    this.yaş++;
    console.log(`${this.tamAdGetir()} şimdi ${this.yaş} yaşında.`);
  }
}
// Sınıftan yeni bir nesne oluşturma
const kişi1 = new Kişi("Ali", "Can", 30);
console.log(kişi1.tamAdGetir()); // Çıktı: Ali Can
const kişi2 = new Kişi("Ayşe", "Yılmaz", 25);
kişi2.yaşınıArtır(); // Çıktı: Ayşe Yılmaz şimdi 26 yaşında.
Örnek 2: Kalıtım (Inheritance) Kullanımı
Sınıflar, extends anahtar kelimesiyle başka bir sınıftan kalıtım alabilir. Bu, alt sınıfın üst sınıfın özelliklerini ve metotlarını miras almasını sağlar.
class Çalışan extends Kişi {
  constructor(ad, soyad, yaş, pozisyon) {
    super(ad, soyad, yaş); // Üst sınıfın constructor'ını çağırır
    this.pozisyon = pozisyon;
  }
  çalışmaDurumu() {
    return `${this.tamAdGetir()} ${this.pozisyon} pozisyonunda çalışmaktadır.`;
  }
}
const çalışan1 = new Çalışan("Deniz", "Ak", 35, "Yazılımcı");
console.log(çalışan1.tamAdGetir()); // Çıktı: Deniz Ak (Kişi sınıfından miras alındı)
console.log(çalışan1.çalışmaDurumu()); // Çıktı: Deniz Ak Yazılımcı pozisyonunda çalışmaktadır.
çalışan1.yaşınıArtır(); // Çıktı: Deniz Ak şimdi 36 yaşında. (Kişi sınıfından miras alındı)
Örnek 3: Getter, Setter ve Statik Metot Kullanımı
Bu örnek, bir sınıf içinde getter, setter ve statik metotların nasıl tanımlanıp kullanılacağını göstermektedir.
class Ayarlar {
  constructor(tema) {
    this._tema = tema; // Özel bir özellik gibi davranır
  }
  get tema() {
    return this._tema;
  }
  set tema(yeniTema) {
    if (yeniTema === "açık" || yeniTema === "koyu") {
      this._tema = yeniTema;
      console.log(`Tema ${yeniTema} olarak ayarlandı.`);
    } else {
      console.warn("Geçersiz tema değeri. 'açık' veya 'koyu' kullanın.");
    }
  }
  static uygulamaBilgisi() {
    return "Uygulama Adı: MyWebApp v1.0";
  }
}
const kullanıcıAyarları = new Ayarlar("koyu");
console.log(kullanıcıAyarları.tema); // Çıktı: koyu (getter çağrıldı)
kullanıcıAyarları.tema = "açık"; // setter çağrıldı
console.log(kullanıcıAyarları.tema); // Çıktı: açık
kullanıcıAyarları.tema = "mavi"; // Geçersiz tema uyarısı
console.log(Ayarlar.uygulamaBilgisi()); // Çıktı: Uygulama Adı: MyWebApp v1.0 (statik metot çağrıldı)
Hoisting Yok: Fonksiyon bildirimlerinin aksine, JavaScript sınıfları "hoist" edilmezler. Yani, bir sınıfı tanımlamadan önce kullanamazsınız. Önce sınıfı tanımlamalı, sonra örneğini oluşturmalısınız.
Tek Sorumluluk Prensibi: Her sınıfın tek bir sorumluluğu olmaya özen gösterin. Bu, kodunuzu daha okunabilir, sürdürülebilir ve test edilebilir hale getirir.
this Anahtar Kelimesi: Sınıf metotları içinde this anahtar kelimesi, o metodu çağıran sınıf örneğine (instance) referans verir. this'in bağlamı (context) fonksiyonun nasıl çağrıldığına bağlı olarak değişebilir, bu nedenle özellikle callback fonksiyonlarında dikkatli olun (gerekirse arrow fonksiyonları veya .bind() kullanın).
super() Kullanımı: Alt sınıfların constructor metodunda, üst sınıfın constructor metodunu çağırmak için super() kullanılmalıdır. super() çağrılmadan önce this anahtar kelimesine erişilemez.
Sınıflar Fonksiyondur: JavaScript sınıfları aslında özel bir tür fonksiyondur. typeof SınıfAdı ifadesi "function" döndürür. Bu, JavaScript'in prototip tabanlı doğasının bir yansımasıdır.
                            JavaScript, sürekli gelişen bir programlama dilidir ve bu gelişim, ECMAScript (ES) standartları aracılığıyla tanımlanır. ECMAScript, dilin temel özelliklerini, sözdizimini ve semantiğini belirleyen standarttır; JavaScript ise bu standardın en bilinen uygulamasıdır. Geliştiricilerin modern web uygulamaları oluşturabilmesi için, dilin farklı versiyonlarında sunulan yeni özellikleri anlaması ve bunları etkin bir şekilde kullanması kritik öneme sahiptir. Bu makale, ECMAScript versiyonlarının JavaScript geliştirme üzerindeki etkilerini ve modern özellikleri projelerinizde nasıl uygulayacağınızı detaylandırmaktadır.
JavaScript'in sözdizimi, ECMAScript standartlarının her yeni sürümüyle birlikte evrimleşmektedir. Bu evrim, daha okunaklı, verimli ve güçlü kod yazma imkanı sunar. En belirgin değişikliklerden biri, değişken tanımlama mekanizmasında yaşanmıştır. ES6 (ECMAScript 2015) öncesinde sadece var anahtar kelimesi kullanılırken, ES6 ile birlikte let ve const anahtar kelimeleri tanıtılmıştır. Bu yeni anahtar kelimeler, blok kapsam (block-scoping) ve yeniden atama kısıtlamaları gibi önemli iyileştirmeler getirmiştir.
// ES5 (veya öncesi) değişken tanımlama
var degiskenAdet = 10;
if (true) {
  var degiskenAdet = 20; // Aynı kapsamda yeniden tanımlanabilir, beklenen davranışı değiştirebilir.
  console.log(degiskenAdet); // Çıktı: 20
}
console.log(degiskenAdet); // Çıktı: 20 (Beklenenden farklı olabilir)
// ES6+ ile değişken tanımlama
let sayac = 0;
const PI = 3.14;
if (true) {
  let sayac = 1; // Yeni bir blok kapsamlı değişken
  console.log(sayac); // Çıktı: 1
  // PI = 3.14159; // Hata: const ile tanımlanan bir değişken yeniden atanamaz.
}
console.log(sayac); // Çıktı: 0 (Blok dışındaki orijinal değişken)
ECMAScript, her yıl yeni bir sürümle güncellenerek dile yeni özellikler ekler. Bu sürümler genellikle ES5 (2009), ES6/ES2015, ES2016, ES2017 ve devam eden yıllık güncellemeler şeklinde adlandırılır.
ECMAScript Nedir? ECMAScript, Ecma International tarafından standardize edilen bir betik dili belirtimidir. JavaScript, JScript ve ActionScript gibi diller bu standardın uygulamalarıdır.
Sürüm Evrimi ve Özellikler: Her yeni sürüm, dile yeni sözdizimi ve API'lar ekler. Örneğin, ES6 ile ok fonksiyonları (=>), sınıf sözdizimi (class), şablon dizeleri (template literals), destructuring atama ve modüller (import/export) gibi önemli özellikler gelmiştir. Daha sonraki sürümlerde ise async/await (ES2017), nesne yayma operatörü (object spread operator) ve dinamik içe aktarmalar (dynamic imports) gibi özellikler eklenmiştir.
Uyumluluk Sorunları: Yeni ECMAScript özellikleri her tarayıcı veya Node.js ortamında hemen desteklenmeyebilir. Eski tarayıcılar, modern JavaScript kodunu anlayamayabilir ve bu durum hatalara yol açabilir.
Transpilasyon ve Polyfiller: Bu uyumluluk sorununu çözmek için iki ana yöntem kullanılır:
Transpilasyon: Modern JavaScript kodunu, eski JavaScript versiyonlarına dönüştürme işlemidir. En popüler transpilatör Babel'dir. Bu sayede geliştiriciler yeni özelliklerle kod yazabilirken, sonuçta ortaya çıkan kod geniş bir yelpazedeki eski ortamlarla uyumlu olur.
Polyfiller: Eski tarayıcılarda eksik olan modern JavaScript özelliklerini (örneğin, Promise veya Array.prototype.includes gibi API'lar) taklit eden kod parçacıklarıdır. Transpilasyon sözdizimini dönüştürürken, polyfiller API'ların eksik işlevselliğini sağlar.
Aşağıdaki örnekler, farklı ECMAScript versiyonlarında tanıtılan özelliklerin kullanımını ve bunların eski yaklaşımlarla karşılaştırmasını göstermektedir.
Örnek 1: Ok Fonksiyonları (Arrow Functions) - ES6
Ok fonksiyonları, daha kısa ve daha sezgisel bir fonksiyon sözdizimi sunar ve this bağlamının nasıl işlediği konusunda önemli değişiklikler yapar.
// ES5 fonksiyon tanımı
function sumES5(a, b) {
  return a + b;
}
console.log("ES5 Toplam:", sumES5(5, 3)); // Çıktı: ES5 Toplam: 8
// ES6 Ok Fonksiyonu
const sumES6 = (a, b) => a + b;
console.log("ES6 Toplam:", sumES6(5, 3)); // Çıktı: ES6 Toplam: 8
// 'this' bağlamı farkı
function CounterES5() {
  this.count = 0;
  setInterval(function() {
    // 'this' burada Global/Window nesnesine işaret eder (strict mode'da undefined)
    // Bu yüzden 'self = this' gibi bir yaklaşıma ihtiyaç duyulur.
    console.log("ES5 Counter:", this.count++);
  }, 1000);
}
// new CounterES5(); // Çalıştırıldığında hata verebilir veya beklenenden farklı çalışır
function CounterES6() {
  this.count = 0;
  setInterval(() => {
    // Ok fonksiyonları, tanımlandıkları kapsamdaki 'this' değerini korur (lexical this).
    console.log("ES6 Counter:", this.count++);
  }, 1000);
}
// new CounterES6(); // Beklendiği gibi çalışır
Örnek 2: Asenkron İşlemler için async/await - ES2017
async ve await anahtar kelimeleri, Promise tabanlı asenkron kodu senkron koda benzer bir şekilde yazmayı sağlayarak okunabilirliği artırır.
// Bir Promise döndüren örnek fonksiyon
function veriGetir() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Veri başarıyla alındı!");
    }, 2000);
  });
}
// ES5/ES6 Promises ile asenkron işlem
veriGetir().then(mesaj => {
  console.log("Promise ile:", mesaj); // 2 saniye sonra çalışır
});
// ES2017 async/await ile asenkron işlem
async function veriyiIsle() {
  console.log("Veri bekleniyor...");
  const mesaj = await veriGetir(); // Promise tamamlanana kadar bekler
  console.log("Async/Await ile:", mesaj); // Promise tamamlandıktan sonra çalışır
  console.log("İşlem tamamlandı.");
}
veriyiIsle();
Hedef Ortam Farkındalığı: Kodunuzu yazarken, hedeflediğiniz tarayıcılar ve Node.js sürümleri gibi çalışma ortamlarının hangi ECMAScript özelliklerini desteklediğini daima göz önünde bulundurun. caniuse.com gibi kaynaklar bu konuda size yardımcı olabilir.
Babel ve Webpack Kullanımı: Büyük ölçekli projelerde veya geniş tarayıcı desteği gerektiren durumlarda, Babel gibi bir transpilatör ve Webpack gibi bir bundler kullanmak neredeyse zorunludur. Bu araçlar, modern kodunuzu eski ortamlara uyumlu hale getirirken, aynı zamanda kodunuzu optimize etmenize ve modülleri yönetmenize olanak tanır.
Polyfiller'ı Doğru Kullanın: Transpilatörler sözdizimsel değişiklikleri yönetirken, yeni API'lar için polyfiller'lara ihtiyaç duyulur. Yalnızca projenizin ihtiyaç duyduğu polyfiller'ları dahil ederek paket boyutunu minimumda tutun.
Progressive Enhancement (Aşamalı Geliştirme): Mümkün olduğunda, en yeni özelliklerle kod yazın ve eski ortamlara düşüş (fallback) sağlayın. Bu, modern tarayıcılarda daha zengin bir deneyim sunarken, eski tarayıcılarda temel işlevselliği korur.
Güncel Kalın: ECMAScript standartları her yıl yeni özelliklerle güncellendiği için, dilin en son yeniliklerini takip etmek ve bunları projelerinizde nasıl kullanabileceğinizi öğrenmek önemlidir.
                            JavaScript, web geliştirmenin temel taşlarından biri olmasının yanı sıra, Node.js ile sunucu tarafı uygulamalardan mobil uygulamalara (React Native) ve hatta masaüstü uygulamalarına (Electron) kadar geniş bir alanda kullanılan dinamik ve çok yönlü bir programlama dilidir. Bu kılavuz, JavaScript ile programlama yapmanın temel yapı taşlarını, sözdizimini ve yaygın kullanım senaryolarını adım adım açıklayarak, sağlam bir temel oluşturmanızı hedeflemektedir.
JavaScript kodları, tarayıcılarda veya Node.js gibi çalışma zamanı ortamlarında yorumlanan bir dizi ifade ve deyimden oluşur. Her JavaScript programı, değişken tanımlamaları, operatör kullanımları, kontrol akışı yapıları ve fonksiyon çağrılarının birleşimidir. Temel bir JavaScript programının genel yapısı aşağıdaki gibidir:
// Tek satırlık yorum
/* 
 * Çok satırlı yorum
 */
// Değişken tanımlamaları
let degiskenAdi = deger;
const sabitDeger = baskaDeger;
// İfadeler ve operatörler
let sonuc = degiskenAdi + 5;
// Kontrol akışı (koşullu ifadeler, döngüler)
if (sonuc > 10) {
    // Koşul doğruysa çalışacak kod
} else {
    // Koşul yanlışsa çalışacak kod
}
for (let i = 0; i < 5; i++) {
    // Döngü içinde çalışacak kod
}
// Fonksiyon tanımlamaları ve çağrıları
function fonksiyonAdi(parametre1, parametre2) {
    // Fonksiyonun yapacağı işlemler
    return parametre1 + parametre2;
}
let toplam = fonksiyonAdi(10, 20);
Yukarıdaki sözdiziminde yer alan her bir bileşenin ne anlama geldiğini ve nasıl kullanıldığını detaylı olarak inceleyelim:
Değişkenler: JavaScript'te verileri depolamak için değişkenler kullanılır. Değişkenler, var, let veya const anahtar kelimeleriyle tanımlanır.
let: Blok kapsamlı bir değişken tanımlar. Değeri daha sonra değiştirilebilir.
const: Blok kapsamlı, sadece bir kez değer atanabilen sabit bir değişken tanımlar. Atandıktan sonra değeri değiştirilemez.
var: Fonksiyon kapsamlı bir değişken tanımlar. Modern JavaScript'te genellikle let ve const tercih edilir.
Veri Tipleri: JavaScript, farklı türde verileri işleyebilir. Başlıca veri tipleri şunlardır:
Primitive (İlkel) Tipler: string (metin), number (sayı), boolean (mantıksal doğru/yanlış), null (boş değer), undefined (tanımsız), symbol, bigint.
Reference (Referans) Tipler: object (nesneler, diziler, fonksiyonlar).
Operatörler: Değişkenler ve değerler üzerinde işlemler yapmak için kullanılır. Önemli operatör türleri şunlardır:
Aritmetik Operatörler: +, -, *, /, % (modül).
Atama Operatörleri: =, +=, -=, *=, /=.
Karşılaştırma Operatörleri: == (değer eşitliği), === (değer ve tip eşitliği), !=, !==, >, <, >=, <=.
Mantıksal Operatörler: && (VE), || (VEYA), ! (DEĞİL).
Kontrol Akışı: Programın hangi koşullarda hangi kod bloğunu çalıştıracağını belirler.
if...else if...else: Belirli koşullara göre farklı kod bloklarını çalıştırmak için kullanılır.
switch: Tek bir ifadenin birden çok olası değeri için farklı kod blokları tanımlar.
for, while, do...while: Belirli bir koşul karşılanana kadar veya belirli sayıda tekrarlamak için döngü yapıları.
Fonksiyonlar: Belirli bir görevi yerine getiren yeniden kullanılabilir kod bloklarıdır. Parametre alabilir ve bir değer döndürebilirler. function anahtar kelimesiyle veya ok fonksiyonu (arrow function) sözdizimiyle tanımlanabilirler.
Yukarıda açıklanan kavramları pekiştirmek için çeşitli kod örneklerini inceleyelim:
Örnek 1: Değişken Tanımlama ve Aritmetik İşlem
let fiyat = 150;
const KDV_ORANI = 0.18; // Sabit değer
let KDVtutari = fiyat * KDV_ORANI;
let toplamFiyat = fiyat + KDVtutari;
console.log("Ürün Fiyatı:", fiyat); // Çıktı: Ürün Fiyatı: 150
console.log("KDV Tutarı:", KDVtutari); // Çıktı: KDV Tutarı: 27
console.log("Toplam Fiyat:", toplamFiyat); // Çıktı: Toplam Fiyat: 177
Örnek 2: Koşullu İfade (if-else)
let kullaniciYasi = 20;
if (kullaniciYasi >= 18) {
    console.log("Ehliyet başvurusunda bulunabilirsiniz.");
} else {
    console.log("Ehliyet başvurusu için yaşınız uygun değil.");
}
let puan = 75;
let not;
if (puan >= 90) {
    not = "A";
} else if (puan >= 80) {
    not = "B";
} else if (puan >= 70) {
    not = "C";
} else {
    not = "D";
}
console.log("Öğrencinin Notu:", not); // Çıktı: Öğrencinin Notu: C
Örnek 3: Döngü Kullanımı (for)
let meyveler = ["elma", "armut", "muz", "çilek"];
for (let i = 0; i < meyveler.length; i++) {
    console.log("Benim favori meyvem: " + meyveler[i]);
}
/* Çıktı:
Benim favori meyvem: elma
Benim favori meyvem: armut
Benim favori meyvem: muz
Benim favori meyvem: çilek
*/
Örnek 4: Fonksiyon Tanımlama ve Çağırma
// İki sayıyı toplayan bir fonksiyon
function topla(sayi1, sayi2) {
    return sayi1 + sayi2;
}
let sonuc1 = topla(5, 7);
console.log("5 + 7 =", sonuc1); // Çıktı: 5 + 7 = 12
// İki sayıyı çarpan bir ok fonksiyonu
const carp = (sayi1, sayi2) => {
    return sayi1 * sayi2;
};
let sonuc2 = carp(4, 6);
console.log("4 * 6 =", sonuc2); // Çıktı: 4 * 6 = 24
Noktalı Virgül (;) Kullanımı: JavaScript'te ifadelerin sonunda noktalı virgül kullanmak genellikle iyi bir pratiktir, ancak bazı durumlarda JavaScript motoru otomatik olarak ekleyebilir (Automatic Semicolon Insertion - ASI). Yine de belirsizliği önlemek ve kodunuzu daha okunur kılmak için manuel olarak eklenmesi önerilir.
let ve const Tercihi: Modern JavaScript'te değişken tanımlarken her zaman var yerine let veya const kullanın. Bu, kapsam (scoping) sorunlarını azaltır ve kodunuzu daha öngörülebilir hale getirir. Değeri değişmeyecekse const, değişecekse let kullanın.
Tip Zorlaması (Type Coercion): JavaScript, esnek bir dile sahip olduğundan, bazı durumlarda farklı veri tipleri arasında otomatik dönüşümler yapar. Örneğin, "5" + 2 ifadesi "52" sonucunu verirken, "5" - 2 ifadesi 3 sonucunu verir. Bu durum, beklenmedik hatalara yol açabileceği için dikkatli olunmalıdır. Kesin tip karşılaştırmaları için === (üç eşit) operatörünü kullanın.
Yorum Satırları: Kodunuzu açıklamak için yorum satırlarını kullanın. Tek satırlık yorumlar için //, çok satırlık yorumlar için /* ... */ kullanabilirsiniz. Bu, kodunuzun başkaları (ve gelecekteki siz) tarafından daha kolay anlaşılmasını sağlar.
Hata Ayıklama (Debugging): Kodunuzdaki hataları bulmak için console.log() fonksiyonunu sıkça kullanın. Bu, değişkenlerin değerlerini, fonksiyonların çağrılıp çağrılmadığını veya bir kod bloğuna girilip girilmediğini kontrol etmenize yardımcı olur.
                            JavaScript, web sayfalarını etkileşimli hale getirmek için kullanıcı eylemlerine veya tarayıcı olaylarına tepki verme yeteneği sağlar. Bu tepkiler, 'olaylar' (events) aracılığıyla yönetilir. Bir kullanıcı bir düğmeye tıkladığında, bir form gönderdiğinde veya fare imlecini bir öğenin üzerine getirdiğinde, JavaScript bu olayları dinleyebilir ve tanımlanan işlevleri çalıştırabilir. Bu makale, JavaScript olaylarının temel kullanımını, sözdizimini ve pratik uygulamalarını detaylandıracaktır.
JavaScript'te bir DOM öğesine olay dinleyicisi eklemenin en yaygın ve önerilen yolu EventTarget.addEventListener() metodunu kullanmaktır. Bu metod, belirli bir olay türü gerçekleştiğinde çalıştırılacak bir işlevi (handler) kaydeder.
target.addEventListener(event, listener, [options]);
EventTarget.addEventListener() metodu üç ana argüman alır:
target: Olay dinleyicisinin ekleneceği DOM öğesidir. Örneğin, bir düğme, bir metin alanı veya belge kendisi olabilir.
event: Dinlenecek olayın adını belirten bir stringdir. Örnekler arasında 'click', 'mouseover', 'keydown', 'submit' bulunur. Olay adları büyük/küçük harfe duyarlıdır ve genellikle küçük harfle yazılır.
listener: Belirtilen olay gerçekleştiğinde çağrılacak olan işlevdir (callback fonksiyonu). Bu işlev, olayın kendisi hakkında bilgi içeren bir Event nesnesini argüman olarak alabilir.
options (isteğe bağlı): Olay dinleyicisinin davranışını yapılandıran bir nesnedir. En yaygın seçenekler şunlardır:
capture: Bir boolean değeridir. true ise, olay yakalama (capturing) aşamasında, false ise olay kabarcıklanma (bubbling) aşamasında tetiklenir. Varsayılan değer false'tur.
once: Bir boolean değeridir. true ise, olay dinleyicisi olay bir kez tetiklendikten sonra otomatik olarak kaldırılır. Varsayılan değer false'tur.
passive: Bir boolean değeridir. true ise, dinleyicinin event.preventDefault() çağrısı yapmayacağını belirtir. Bu, özellikle kaydırma (scrolling) olaylarında performansı artırabilir. Varsayılan değer false'tur.
Aşağıdaki örnekler, JavaScript olaylarının çeşitli kullanım senaryolarını göstermektedir.
Bir HTML düğmesine tıklandığında konsola bir mesaj yazdıran basit bir örnek.
Bir metin giriş alanındaki değer her değiştiğinde bu değişikliği yakalayan bir örnek.
Girilen Değer: 
Bir öğenin üzerine fare imleci geldiğinde ve ayrıldığında farklı işlevleri çalıştıran bir örnek.
    Fareyi Üzerime Getir
Dinleyiciyi Kaldırma: Performans ve bellek sızıntılarını önlemek için, özellikle tek seferlik olaylarda veya bileşenler kaldırıldığında EventTarget.removeEventListener() metodunu kullanarak olay dinleyicilerini kaldırmak önemlidir. addEventListener ile aynı argümanlar kullanılmalıdır (aynı fonksiyon referansı dahil).
Olay Nesnesi: Olay dinleyici fonksiyonuna otomatik olarak geçirilen Event nesnesi, olayın türü (event.type), hedefi (event.target), tuş bilgisi (event.key, event.keyCode) gibi değerli bilgiler içerir.
event.preventDefault(): Bazı olayların varsayılan tarayıcı davranışları vardır (örneğin, bir bağlantıya tıklamak sizi başka bir sayfaya götürür veya bir form göndermek sayfayı yeniler). Bu varsayılan davranışları durdurmak için olay nesnesi üzerindeki event.preventDefault() metodunu kullanabilirsiniz.
Olay Kabarcıklanması ve Yakalama: Olaylar, DOM ağacında yukarı (kabarcıklanma) veya aşağı (yakalama) doğru yayılır. addEventListener metodunun üçüncü argümanı (veya options nesnesindeki capture özelliği) bu davranışı kontrol etmenizi sağlar. Çoğu durumda, varsayılan kabarcıklanma davranışı yeterlidir.
this Anahtar Kelimesi: Bir olay dinleyicisi içinde this anahtar kelimesi, olayın gerçekleştiği DOM öğesini (event.currentTarget) ifade eder. Ancak, arrow fonksiyonlar kullanıldığında this, tanımlandığı kapsayıcı kapsamı korur.
                            Modern web uygulamalarının karmaşıklığı, beklenmedik durumların veya hataların ortaya çıkma olasılığını artırmaktadır. JavaScript, bu tür durumları yönetmek için yerleşik bir mekanizma sunar: Error nesnesi. Bu nesne, çalışma zamanı hatalarını temsil etmek, onları yakalamak ve uygun şekilde ele almak için kritik bir araçtır. Uygulama kararlılığını ve kullanıcı deneyimini sağlamak adına Error nesnesinin etkin kullanımı, her JavaScript geliştiricisinin sahip olması gereken temel bir yetkinliktir.
JavaScript'te bir hata nesnesi oluşturmak için Error yapıcısını (constructor) kullanırız. Bu, programatik olarak bir hata durumunu belirtmenin en yaygın yoludur.
new Error([message[, fileName[, lineNumber]]])Error yapıcısının aldığı parametreler ve Error nesnesinin temel özellikleri aşağıda detaylandırılmıştır:
message: Hatanın kısa ve açıklayıcı bir metinle ifade edildiği bir String değeridir. Hata nesnesinin temel içeriğini oluşturur.
fileName (İsteğe Bağlı): Hatanın meydana geldiği dosyanın yolunu belirten bir String değeridir. Genellikle hata yakalama mekanizmaları tarafından otomatik olarak doldurulur.
lineNumber (İsteğe Bağlı): Hatanın meydana geldiği dosyadaki satır numarasını belirten bir Number değeridir. Bu da genellikle otomatik olarak atanır.
Error nesnesinin kendisi, bu parametrelere ek olarak iki önemli özelliğe sahiptir:
name: Hata türünün adını belirten bir String değeridir (örneğin, 'Error', 'TypeError', 'ReferenceError'). Özel hata türleri oluşturulduğunda bu özellik özelleştirilebilir.
stack: Hatanın çağrı yığınını (call stack) gösteren bir String değeridir. Hatanın nerede ve nasıl oluştuğunu anlamak için son derece faydalıdır.
Aşağıdaki örnekler, Error nesnesinin JavaScript uygulamalarında nasıl kullanılabileceğini göstermektedir.
Örnek 1: Temel Hata Fırlatma ve Yakalama
Bir fonksiyonun belirli bir koşulu karşılamadığı durumlarda programın akışını durdurmak ve bir hata durumu bildirmek için throw new Error() kullanılır. try...catch bloğu ile bu hatalar yakalanabilir.
function bolmeIslemi(sayi1, sayi2) {
  if (sayi2 === 0) {
    throw new Error("Sıfıra bölme hatası: Bölen sıfır olamaz.");
  }
  return sayi1 / sayi2;
}
try {
  console.log(bolmeIslemi(10, 2)); // Çıktı: 5
  console.log(bolmeIslemi(10, 0)); // Bu satır bir hata fırlatacak
} catch (e) {
  console.error("Bir hata oluştu:", e.message);
  console.error("Hata adı:", e.name);
  console.error("Hata yığını:", e.stack);
}Örnek 2: Özel Hata Türü Oluşturma
Uygulamaya özgü hata durumlarını daha spesifik bir şekilde yönetmek için Error nesnesinden türetilmiş özel hata sınıfları oluşturulabilir. Bu, hata türlerinin daha kolay ayırt edilmesini ve işlenmesini sağlar.
class GecersizGirdiHatasi extends Error {
  constructor(message) {
    super(message);
    this.name = "GecersizGirdiHatasi"; // Hatanın adını özelleştiriyoruz
  }
}
function veriIsle(veri) {
  if (typeof veri !== 'number' || veri < 0) {
    throw new GecersizGirdiHatasi("Girdi pozitif bir sayı olmalıdır.");
  }
  return veri * 2;
}
try {
  console.log(veriIsle(5)); // Çıktı: 10
  console.log(veriIsle(-3)); // Bu satır özel bir hata fırlatacak
} catch (e) {
  if (e instanceof GecersizGirdiHatasi) {
    console.error("Geçersiz girdi hatası yakalandı:", e.message);
  } else {
    console.error("Beklenmeyen bir hata oluştu:", e.message);
  }
}Örnek 3: try...catch...finally Kullanımı
try...catch...finally yapısı, hata oluşsa da oluşmasa da belirli kod bloklarının çalıştırılmasını garanti eder. Bu, kaynakları temizlemek veya bazı işlemleri tamamlamak için kullanışlıdır.
function dosyaOku(dosyaAdi) {
  let dosyaAcik = false;
  try {
    console.log(`${dosyaAdi} dosyası açılıyor...`);
    dosyaAcik = true;
    // Simulate an error
    if (dosyaAdi === "hatali.txt") {
      throw new Error("Dosya okunamadı: Erişim reddedildi.");
    }
    console.log(`${dosyaAdi} dosya içeriği işleniyor.`);
    return "Dosya içeriği...";
  } catch (e) {
    console.error("Hata:", e.message);
    return null;
  } finally {
    if (dosyaAcik) {
      console.log(`${dosyaAdi} dosyası kapatılıyor.`);
    }
  }
}
console.log(dosyaOku("veri.txt"));
console.log("\n--- Yeni İşlem ---\n");
console.log(dosyaOku("hatali.txt"));Spesifik Hata Türleri Kullanımı: JavaScript, TypeError, ReferenceError, RangeError gibi çeşitli yerleşik hata türleri sunar. Mümkün olduğunca hatanın doğasına uygun spesifik hata türlerini kullanmaya özen gösterin. Bu, hata ayıklamayı ve hata işleme mantığını basitleştirir.
Hataları Bastırmayın: Bir try...catch bloğunda hatayı yakalayıp hiçbir işlem yapmamak (boş bırakmak), uygulamanızdaki sorunların gizlenmesine neden olur. Hataları her zaman uygun bir şekilde günlüğe kaydedin veya kullanıcıya bildirin.
finally Bloğunun Önemi: Kaynakları (dosya bağlantıları, ağ istekleri vb.) serbest bırakmak veya belirli bir işlemi tamamlamak için finally bloğunu kullanın. Bu blok, hata oluşsa da oluşmasa da her zaman çalıştırılır.
Geniş Kapsamlı try...catch Bloklarından Kaçının: Tüm uygulamanızı tek bir try...catch bloğuna sarmak, hangi hatanın nerede meydana geldiğini anlamayı zorlaştırır. Hata yakalama bloklarınızı, hata potansiyeli olan belirli işlevlere veya kod parçalarına odaklayın.
Üretim Ortamında Hata İzleme: Canlı sistemlerde oluşan hataları izlemek için Sentry, Bugsnag gibi üçüncü taraf hata izleme hizmetlerini kullanmayı düşünün. Bu hizmetler, hata raporlarını toplar, analiz eder ve geliştiricilere anında bildirimler gönderir.
                            JavaScript'te düzenli ifadeler (Regular Expressions veya kısaca RegExp), metin içindeki desenleri eşleştirmek, aramak, değiştirmek ve doğrulamak için güçlü bir araçtır. Bu kılavuz, JavaScript ortamında RegExp'in nasıl tanımlandığını ve kullanıldığını, temel sözdiziminden başlayarak çeşitli metotlarla pratik uygulamalarına kadar adım adım açıklamaktadır.
JavaScript'te düzenli ifadeler iki ana şekilde oluşturulabilir: bir RegExp literal'i veya RegExp kurucusu kullanılarak.
Bir RegExp literal'i, deseni iki eğik çizgi (/) arasına alarak oluşturulur ve isteğe bağlı olarak sonuna bayraklar eklenir:
/desen/bayraklarBir RegExp kurucusu ise, deseni ve bayrakları string olarak alır:
new RegExp("desen", "bayraklar")Literal kullanımı genellikle daha basit ve performanttır, ancak desenin veya bayrakların çalışma zamanında dinamik olarak oluşturulması gerektiğinde kurucu yöntemi tercih edilir.
Yukarıdaki sözdiziminde yer alan desen ve bayraklar bileşenleri aşağıdaki gibi açıklanabilir:
Desen (Pattern): Eşleştirilmek istenen karakter dizilerini veya kalıpları tanımlar. Bu, sabit karakterler, özel karakterler (örneğin, . herhangi bir karakteri eşleştirmek için), niceleyiciler (örneğin, + bir veya daha fazla kez eşleştirmek için) ve karakter sınıfları (örneğin, [0-9] bir rakamı eşleştirmek için) içerebilir.
Bayraklar (Flags): Düzenli ifadenin eşleştirme davranışını değiştiren isteğe bağlı tek karakterlerdir. En yaygın kullanılan bayraklar şunlardır:
g (global): Desenin tüm eşleşmelerini bulur, ilk eşleşmeden sonra durmaz.
i (case-insensitive): Büyük/küçük harf duyarsız eşleştirme yapar.
m (multiline): Çok satırlı giriş dizilerinde ^ ve $ karakterlerinin her satırın başında ve sonunda eşleşmesini sağlar.
u (unicode): Deseni Unicode kod noktaları dizisi olarak ele alır.
s (dotAll): . (nokta) karakterinin satır sonu karakterleri dahil herhangi bir karakterle eşleşmesini sağlar.
d (hasIndices): Eşleşen alt dizelerin başlangıç ve bitiş indekslerini içeren bir dizi döndürür.
JavaScript'teki string metotları, düzenli ifadelerle birlikte kullanılarak metin üzerinde çeşitli işlemler yapılmasına olanak tanır. İşte bazı temel metotlar ve örnek kullanımları:
1. RegExp.prototype.test(): Bir string'de bir desenin bulunup bulunmadığını kontrol eder ve bir boolean değer döndürür.
const desen = /elma/;
const metin1 = "Bugün elma yedim.";
const metin2 = "Bugün armut yedim.";
console.log(desen.test(metin1)); // true
console.log(desen.test(metin2)); // false2. String.prototype.match(): Bir string'de deseni arar ve tüm eşleşmeleri içeren bir dizi döndürür. g bayrağı yoksa sadece ilk eşleşmeyi döndürür.
const desen = /elma/g;
const metin = "Yeşil elma, kırmızı elma ve sarı elma.";
const eslesmeler = metin.match(desen);
console.log(eslesmeler); // ["elma", "elma", "elma"]
const desenBuyukKucuk = /Elma/gi; // Büyük/küçük harf duyarsız ve global
const eslesmelerBuyukKucuk = metin.match(desenBuyukKucuk);
console.log(eslesmelerBuyukKucuk); // ["elma", "elma", "elma"]3. String.prototype.replace(): Bir string'deki desene uyan kısımları başka bir string ile değiştirir.
const desen = /elma/g;
const metin = "Yeşil elma, kırmızı elma.";
const yeniMetin = metin.replace(desen, "armut");
console.log(yeniMetin); // "Yeşil armut, kırmızı armut."
const desenRakamlar = /\d+/g; // Bir veya daha fazla rakamı eşleştir
const metinRakamlar = "Toplam 123 adet ürün, fiyat 45.67 TL.";
const yeniMetinRakamlar = metinRakamlar.replace(desenRakamlar, "XXX");
console.log(yeniMetinRakamlar); // "Toplam XXX adet ürün, fiyat XXX.XX TL."4. String.prototype.search(): Bir string'de deseni arar ve ilk eşleşmenin indeksini döndürür. Eşleşme bulunamazsa -1 döndürür. g bayrağı bu metot için anlamsızdır.
const desen = /kırmızı/;
const metin = "Yeşil elma, kırmızı elma.";
const indeks = metin.search(desen);
console.log(indeks); // 12 (k harfinin indeksi)
const desenYok = /mavi/;
const indeksYok = metin.search(desenYok);
console.log(indeksYok); // -15. String.prototype.split(): Bir string'i, belirtilen bir desen veya karakter dizisi kullanarak bir diziye böler.
const desen = /\s*,\s*/; // Virgül etrafındaki boşlukları da yakalar
const metin = "elma, armut , muz, kiraz";
const meyveler = metin.split(desen);
console.log(meyveler); // ["elma", "armut", "muz", "kiraz"]
const desenKarakter = /a/g; // Her 'a' karakterinden böl
const kelime = "banana";
const parcalar = kelime.split(desenKarakter);
console.log(parcalar); // ["b", "n", "n", ""] (son 'a'dan sonra boş string)Kaçış Karakterleri: Özel anlamı olan karakterleri (örneğin, ., *, +, ?, ^, $, (, ), [, ], {, }, |, \) desen içinde literal olarak kullanmak isterseniz, önüne ters eğik çizgi (\) ekleyerek kaçış yapmalısınız. Örneğin, bir noktayı (.) eşleştirmek için /\./ kullanın.
Dinamik Desenler: Deseni bir string'den oluşturuyorsanız (new RegExp("desen")), bu string içindeki kaçış karakterlerini (\) iki kez kaçış yapmanız gerekebilir (örneğin, new RegExp("\\d+")).
Performans: Çok karmaşık veya verimsiz düzenli ifadeler, özellikle büyük metinler üzerinde çalışırken performans sorunlarına neden olabilir. Deseninizi mümkün olduğunca spesifik ve basit tutmaya çalışın.
Stateful RegExp: g bayrağına sahip bir RegExp nesnesi, lastIndex özelliğini günceller. Aynı RegExp nesnesini birden fazla kez test() veya exec() ile çağırırsanız, eşleşmeler bir önceki çağrının bittiği yerden devam eder. Bu durum, beklenmedik sonuçlara yol açabilir, bu yüzden dikkatli olun veya her kullanımda yeni bir RegExp literal'i oluşturmayı düşünün.
Online Araçlar: Düzenli ifadeleri test etmek ve geliştirmek için Regex101 veya RegExr gibi çevrimiçi araçları kullanmak, karmaşık desenleri anlamanıza ve hata ayıklamanıza yardımcı olabilir.
                            
JavaScript, web uygulamalarının dinamik etkileşimini sağlayan güçlü bir dil olmakla birlikte, karmaşık matematiksel hesaplamalar için de sağlam bir temel sunar. Bu bağlamda, JavaScript'in yerleşik Math nesnesi, standart matematiksel işlevleri ve sabitleri programcıların kullanımına sunarak, sayısal işlemlerin kolay ve verimli bir şekilde gerçekleştirilmesini sağlar. Bir sınıf olmamasına rağmen, Math nesnesi tüm özelliklerini ve metotlarını statik olarak sunar; bu da onun doğrudan erişilebilir olduğu ve örneklendirilmesinin gerekmediği anlamına gelir. Bu makalede, Math nesnesinin temel kullanımından gelişmiş uygulamalarına kadar uzanan çeşitli yönlerini inceleyeceğiz.
JavaScript'teki Math nesnesi, doğrudan erişilebilen statik metotlar ve özellikler içerir. Bu, Math nesnesini oluşturmanıza gerek olmadığı anlamına gelir; tüm metotlarına ve özelliklerine doğrudan Math. önekiyle erişilebilir.
Genel kullanım yapısı aşağıdaki gibidir:
Math.propertyName;
Math.methodName(arg1, arg2, ...);
Math nesnesi bir yapıcıya (constructor) sahip değildir ve tüm metotları ile özellikleri statiktir. Bu, new Math() şeklinde bir kullanımın geçersiz olduğu ve hata döndüreceği anlamına gelir. Bunun yerine, Math.PI gibi bir sabite veya Math.random() gibi bir metoda doğrudan erişilir.
Aşağıda, Math nesnesinin sıkça kullanılan bazı metotları ve özellikleri detaylı olarak açıklanmıştır:
Math.PI: Bir dairenin çevresinin çapına oranı olan pi (π) sayısının değerini döndürür.
Math.abs(x): Bir sayının mutlak değerini döndürür.
Math.round(x): Bir sayıyı en yakın tam sayıya yuvarlar. .5 durumunda yukarı yuvarlar.
Math.floor(x): Bir sayıyı her zaman aşağıya, en yakın tam sayıya yuvarlar.
Math.ceil(x): Bir sayıyı her zaman yukarıya, en yakın tam sayıya yuvarlar.
Math.random(): 0 (dahil) ile 1 (hariç) arasında rastgele bir ondalık sayı döndürür.
Math.max(x1, x2, ..., xn): Verilen sayılar arasındaki en büyük değeri döndürür.
Math.min(x1, x2, ..., xn): Verilen sayılar arasındaki en küçük değeri döndürür.
Math.pow(x, y): x sayısının y kuvvetini döndürür (xy).
Math.sqrt(x): Bir sayının karekökünü döndürür.
Math.sin(x), Math.cos(x), Math.tan(x): Trigonometrik sinüs, kosinüs ve tanjant değerlerini radyan cinsinden verilen bir açı için döndürür.
Aşağıdaki örnekler, Math nesnesinin farklı metotlarının pratik uygulamalarını göstermektedir.
Örnek 1: Temel Yuvarlama İşlemleri ve Pi Sabiti Kullanımı
// Pi (π) değerini alma
const piValue = Math.PI;
console.log("Pi değeri:", piValue); // Çıktı: Pi değeri: 3.141592653589793
// Sayı yuvarlama örnekleri
let num1 = 4.7;
let num2 = 4.3;
let num3 = 4.5;
let num4 = -4.7;
console.log("Math.round(4.7):", Math.round(num1));   // Çıktı: 5
console.log("Math.round(4.3):", Math.round(num2));   // Çıktı: 4
console.log("Math.round(4.5):", Math.round(num3));   // Çıktı: 5
console.log("Math.floor(4.7):", Math.floor(num1));   // Çıktı: 4
console.log("Math.ceil(4.3):", Math.ceil(num2));     // Çıktı: 5
console.log("Math.abs(-4.7):", Math.abs(num4));     // Çıktı: 4.7Örnek 2: Rastgele Sayı Üretimi
Math.random() metodu 0 (dahil) ile 1 (hariç) arasında bir sayı üretir. Belirli bir aralıkta rastgele tam sayı üretmek için bu metot Math.floor() ile birlikte kullanılabilir.
// 0 ile 1 arasında rastgele ondalık sayı
const randomDecimal = Math.random();
console.log("Rastgele ondalık:", randomDecimal); // Örn: 0.123456789
// 1 ile 10 arasında rastgele tam sayı (1 ve 10 dahil)
function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
const randomNum = getRandomInt(1, 10);
console.log("1-10 arası rastgele tam sayı:", randomNum); // Örn: 7Örnek 3: Üs Alma ve Karekök Hesaplama
// Üs alma (2^3 = 8)
const powerResult = Math.pow(2, 3);
console.log("2 üzeri 3:", powerResult); // Çıktı: 8
// Karekök alma (karekök 81 = 9)
const sqrtResult = Math.sqrt(81);
console.log("81'in karekökü:", sqrtResult); // Çıktı: 9Örnek 4: En Büyük ve En Küçük Değeri Bulma
const numbers = [10, 5, 20, 8, 15];
// Array'deki en büyük ve en küçük değeri bulmak için spread operatörü (...) kullanılır.
const maxVal = Math.max(...numbers);
const minVal = Math.min(...numbers);
console.log("En büyük değer:", maxVal); // Çıktı: 20
console.log("En küçük değer:", minVal); // Çıktı: 5
// Doğrudan sayılarla da kullanılabilir
console.log("max(1, 5, 2, 9):", Math.max(1, 5, 2, 9)); // Çıktı: 9Statik Nesne: Math bir nesne olmasına rağmen, bir yapıcıya sahip değildir ve doğrudan new Math() ile örneklendirilemez. Tüm metotları ve özellikleri statiktir ve doğrudan Math.metotAdı() veya Math.özellikAdı şeklinde çağrılır.
Radyan Kullanımı: Trigonometrik fonksiyonlar (Math.sin(), Math.cos(), Math.tan()) açıları derece yerine radyan cinsinden bekler. Dereceyi radyana çevirmek için derece * (Math.PI / 180) formülünü kullanabilirsiniz.
Math.random() Aralığı: Math.random() her zaman 0 (dahil) ile 1 (hariç) arasında bir değer döndürür. Belirli bir aralıkta (min, max) tam sayı elde etmek için genellikle Math.floor(Math.random() * (max - min + 1)) + min formülü kullanılır.
Floating-Point Hassasiyeti: JavaScript, diğer programlama dillerinde olduğu gibi, kayan noktalı sayılarla (floating-point numbers) çalışırken hassasiyet sorunları yaşayabilir. Bu durum, özellikle ondalık sayılarla yapılan karmaşık hesaplamalarda beklenmedik sonuçlara yol açabilir. Örneğin, 0.1 + 0.2 doğrudan 0.3 yerine 0.30000000000000004 sonucunu verebilir.
Type Coercion: Math metotları, kendisine geçirilen argümanları otomatik olarak sayısal tiplere dönüştürmeye çalışır. Geçersiz bir değer (örneğin, bir string) geçirildiğinde NaN (Not-a-Number) döndürebilir.
                            Map nesnesi, JavaScript'te anahtar-değer çiftlerini saklamak için kullanılan güçlü bir veri yapısıdır. Geleneksel nesnelerin (Object) sınırlamalarını aşarak, anahtar olarak herhangi bir veri türünü (nesneler, fonksiyonlar, ilkel değerler) kullanılmasına olanak tanır ve elemanların eklenme sırasını korur. Bu özellikler, Map'i belirli senaryolarda Object'e göre daha esnek ve verimli bir alternatif haline getirir.
Map nesnesi, new Map() yapıcı fonksiyonu kullanılarak oluşturulur. Anahtar-değer çiftleri eklemek, almak ve yönetmek için çeşitli yöntemler sunar.
Yeni bir Map oluşturma:
const myMap = new Map();Başlangıç değerleri ile Map oluşturma:
const initialMap = new Map([
  ['anahtar1', 'değer1'],
  ['anahtar2', 'değer2']
]);Bir anahtar-değer çifti ekleme:
myMap.set('ad', 'Alice');Bir anahtarın değerini alma:
const ad = myMap.get('ad'); // 'Alice'Bir anahtarın varlığını kontrol etme:
const varMi = myMap.has('ad'); // trueBir anahtar-değer çiftini silme:
myMap.delete('ad');Map'teki eleman sayısını alma:
const boyut = myMap.size;Tüm anahtar-değer çiftlerini temizleme:
myMap.clear();Map nesnesi, JavaScript'teki geleneksel Object'lere göre bazı önemli avantajlar sunar ve farklı kullanım senaryolarına hitap eder.
Anahtar Türleri: Geleneksel nesnelerde anahtarlar yalnızca string veya Symbol olabilirken, Map nesneleri anahtar olarak herhangi bir veri türünü (nesneler, fonksiyonlar, diziler, ilkel değerler vb.) kabul edebilir. Bu, özellikle DOM elemanları veya diğer nesneleri doğrudan anahtar olarak kullanmak istediğinizde büyük bir avantaj sağlar.
Eleman Sırası: Map nesneleri, anahtar-değer çiftlerinin eklenme sırasını korur. Bu, üzerinde iterasyon yaparken elemanların hangi sırayla eklendiğini bilmek veya bu sırayı kullanmak istediğinizde önemlidir. Geleneksel nesnelerde özelliklerin sırası garanti edilmez (ancak ES2015'ten sonra bazı durumlarda kısmen garanti edilmeye başlanmıştır, yine de Map kadar güçlü değildir).
Boyut: Map nesnesinin size özelliği, içerdiği anahtar-değer çiftlerinin sayısını doğrudan ve verimli bir şekilde verir. Geleneksel nesnelerde bu bilgiye ulaşmak için genellikle Object.keys(obj).length gibi yöntemler kullanmak gerekir ki bu da her seferinde yeni bir dizi oluşturmayı gerektirir.
Performans: Sık sık anahtar-değer çiftlerinin eklenip silindiği senaryolarda, Map genellikle geleneksel nesnelere göre daha iyi performans sergileyebilir. Özellikle anahtar sayısı arttıkça bu fark daha belirgin hale gelebilir.
Iterasyon: Map nesneleri doğrudan iterable'dır. Bu, for...of döngüleri ile kolayca anahtarlar, değerler veya anahtar-değer çiftleri üzerinde döngü yapmanızı sağlar. map.keys(), map.values() ve map.entries() yöntemleri, ilgili iterable nesneleri döndürür.
Bir Map'e aynı anahtarla yeni bir değer atandığında, mevcut değerin üzerine yazılır. Bu, anahtarların benzersiz olmasını sağlar.
Aşağıdaki örnekler, Map nesnesinin çeşitli kullanım senaryolarını göstermektedir.
Bu örnek, bir Map oluşturmayı, eleman eklemeyi, eleman almayı, varlığını kontrol etmeyi ve silmeyi gösterir.
const kullaniciBilgileri = new Map();
// Eleman ekleme
kullaniciBilgileri.set('id', 101);
kullaniciBilgileri.set('ad', 'Veli');
kullaniciBilgileri.set('soyad', 'Demir');
kullaniciBilgileri.set('aktif', true);
console.log('Kullanıcı Adı:', kullaniciBilgileri.get('ad')); // Çıktı: Kullanıcı Adı: Veli
console.log('ID mevcut mu?', kullaniciBilgileri.has('id')); // Çıktı: ID mevcut mu? true
console.log('Email mevcut mu?', kullaniciBilgileri.has('email')); // Çıktı: Email mevcut mu? false
// Bir elemanı silme
kullaniciBilgileri.delete('aktif');
console.log('Aktif durumu silindi mi?', !kullaniciBilgileri.has('aktif')); // Çıktı: Aktif durumu silindi mi? true
console.log('Map boyutu:', kullaniciBilgileri.size); // Çıktı: Map boyutu: 3
// Tüm elemanları temizleme
kullaniciBilgileri.clear();
console.log('Map temizlendikten sonra boyut:', kullaniciBilgileri.size); // Çıktı: Map temizlendikten sonra boyut: 0Map'in en güçlü yönlerinden biri, anahtar olarak nesneleri kullanabilmesidir. Bu örnek, iki farklı nesneyi anahtar olarak nasıl kullanacağımızı gösterir.
const kullanici1 = { id: 1, ad: 'Ayşe' };
const kullanici2 = { id: 2, ad: 'Fatma' };
const kullaniciRolleri = new Map();
kullaniciRolleri.set(kullanici1, 'Yönetici');
kullaniciRolleri.set(kullanici2, 'Editör');
console.log(kullaniciRolleri.get(kullanici1)); // Çıktı: Yönetici
console.log(kullaniciRolleri.get(kullanici2)); // Çıktı: Editör
// Yeni bir nesne oluşturup aynı değerlere sahip olsa bile farklı bir anahtar olarak kabul edilir.
const kullanici3 = { id: 1, ad: 'Ayşe' };
console.log(kullaniciRolleri.get(kullanici3)); // Çıktı: undefined (çünkü bellekte farklı bir referanstır)Map nesneleri, for...of döngüsü ile kolayca iterate edilebilir. Bu örnek, anahtarlar, değerler ve anahtar-değer çiftleri üzerinde nasıl döngü yapılacağını gösterir.
const urunFiyatlari = new Map([
  ['Laptop', 12000],
  ['Klavye', 500],
  ['Fare', 250]
]);
console.log('--- Anahtar-Değer Çiftleri ---');
for (const [urun, fiyat] of urunFiyatlari) {
  console.log(`${urun}: ${fiyat} TL`);
}
// Çıktı:
// Laptop: 12000 TL
// Klavye: 500 TL
// Fare: 250 TL
console.log('\n--- Sadece Anahtarlar ---');
for (const urun of urunFiyatlari.keys()) {
  console.log(urun);
}
// Çıktı:
// Laptop
// Klavye
// Fare
console.log('\n--- Sadece Değerler ---');
for (const fiyat of urunFiyatlari.values()) {
  console.log(fiyat);
}
// Çıktı:
// 12000
// 500
// 250Map ve dizi arasında kolayca dönüşüm yapabilirsiniz.
// Diziden Map oluşturma
const diziVeri = [['a', 1], ['b', 2], ['c', 3]];
const harita = new Map(diziVeri);
console.log('Diziden Oluşturulan Map:', harita); // Çıktı: Diziden Oluşturulan Map: Map(3) { 'a' => 1, 'b' => 2, 'c' => 3 }
// Map'i diziye dönüştürme (entries olarak)
const haritaDizi = Array.from(harita);
console.log('Map\'in Diziye Dönüştürülmüş Hali (entries):', haritaDizi); // Çıktı: Map'in Diziye Dönüştürülmüş Hali (entries): [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
// Sadece anahtarları diziye dönüştürme
const anahtarlarDizi = [...harita.keys()];
console.log('Map Anahtarları Dizi Olarak:', anahtarlarDizi); // Çıktı: Map Anahtarları Dizi Olarak: [ 'a', 'b', 'c' ]
// Sadece değerleri diziye dönüştürme
const degerlerDizi = [...harita.values()];
console.log('Map Değerleri Dizi Olarak:', degerlerDizi); // Çıktı: Map Değerleri Dizi Olarak: [ 1, 2, 3 ]Anahtar Karşılaştırması: Map'teki anahtarlar, SameValueZero algoritması kullanılarak karşılaştırılır. Bu, === operatörüne benzer ancak NaN değerinin kendisine eşit kabul edilmesi gibi bazı farklılıklar içerir (NaN === NaN false dönerken, Map içinde NaN anahtarı NaN ile eşleşir).
Map vs. Object: Ne zaman hangisini kullanacağınızı iyi belirleyin. Eğer anahtarlarınız yalnızca string veya Symbol ise ve eleman sırası önemli değilse, basit bir Object yeterli olabilir. Ancak anahtarlarınız farklı veri tiplerinde olacaksa, eleman sırasını korumanız gerekiyorsa veya sık sık eleman ekleyip siliyorsanız, Map genellikle daha iyi bir seçimdir.
Serileştirme: Map nesneleri doğrudan JSON.stringify() ile serileştirilemez. Bir Map'i JSON formatına dönüştürmek için önce onu bir diziye veya düz bir nesneye dönüştürmeniz gerekir.
WeakMap: JavaScript ayrıca WeakMap adında bir veri yapısı sunar. WeakMap, yalnızca nesneleri anahtar olarak kabul eder ve anahtarların "zayıf" referanslarını tutar. Bu, anahtar nesneye başka hiçbir referans kalmadığında çöp toplayıcının anahtarı ve ilgili değeri otomatik olarak silmesine olanak tanır. Bellek yönetimi açısından önemlidir, ancak Map'ten farklı bir kullanım senaryosu vardır.
                            JavaScript'te Setler, benzersiz değerlerden oluşan bir koleksiyonu depolamak için kullanılan özel bir nesne türüdür.
Bu veri yapısı, tekrar eden öğelerin otomatik olarak elenmesini sağlayarak veri yönetimi ve manipülasyonunda önemli avantajlar sunar.
Bu makale, JavaScript Setlerinin temel kullanımını, sözdizimini ve pratik uygulamalarını detaylı bir şekilde açıklayacaktır.
Bir Set oluşturmak için new Set() kurucusu kullanılır.
Değerler, Set'in kurucusuna bir iterable (örneğin bir dizi) olarak geçirilebilir veya daha sonra add() metodu ile eklenebilir.
// Boş bir Set oluşturma
const mySet = new Set();
// Başlangıç değerleri ile Set oluşturma
const initialSet = new Set([1, 2, 3, 2, 4]); // initialSet: {1, 2, 3, 4}
// Metotlar
mySet.add(value);      // Bir değer ekler
mySet.delete(value);   // Bir değeri siler
mySet.has(value);      // Bir değerin varlığını kontrol eder
mySet.clear();         // Set'teki tüm öğeleri siler
mySet.size;            // Set'teki öğe sayısını döndürürnew Set([iterable]): Yeni bir Set nesnesi oluşturur. İsteğe bağlı olarak, iterable bir nesne (örneğin bir dizi) alabilir. Bu iterable içindeki tüm öğeler Set'e eklenir. Tekrar eden değerler otomatik olarak göz ardı edilir.
Set.prototype.add(value): Set'e yeni bir değer ekler. Eğer değer zaten Set'te mevcutsa, Set değişmez. Zincirleme çağrılara izin vermek için Set nesnesini döndürür.
Set.prototype.delete(value): Set'ten belirli bir değeri siler. Eğer değer Set'te mevcutsa true, aksi takdirde false döndürür.
Set.prototype.has(value): Belirli bir değerin Set'te olup olmadığını kontrol eder. Varsa true, yoksa false döndürür.
Set.prototype.clear(): Set'teki tüm öğeleri siler ve Set'i boşaltır.
Set.prototype.size: Set'teki benzersiz öğelerin sayısını döndüren bir erişimci özelliğidir.
Set.prototype.forEach(callbackFn[, thisArg]): Set'teki her öğe için bir callback fonksiyonu yürütür. Dizilerdeki forEach metoduna benzer.
Set.prototype.values(), Set.prototype.keys(), Set.prototype.entries(): Set'teki değerleri, anahtarları (Set'lerde anahtarlar ve değerler aynıdır) veya anahtar/değer çiftlerini ([value, value] formatında) içeren yeni bir Iterator nesnesi döndürür.
Aşağıdaki örnekler, JavaScript Setlerinin çeşitli kullanım senaryolarını göstermektedir.
Bir dizideki yinelenen öğeleri kaldırmak ve yalnızca benzersiz değerleri elde etmek için Setleri kullanmak oldukça etkilidir.
const numbers = [1, 2, 3, 4, 2, 1, 5, 6, 3];
const uniqueNumbers = new Set(numbers);
console.log(uniqueNumbers); // Set(6) {1, 2, 3, 4, 5, 6}
// Set'i tekrar bir diziye dönüştürme
const uniqueNumbersArray = [...uniqueNumbers];
console.log(uniqueNumbersArray); // [1, 2, 3, 4, 5, 6]Bir öğenin bir koleksiyonda olup olmadığını hızlıca kontrol etmek için has() metodunu kullanabilirsiniz.
const fruits = new Set(['elma', 'armut', 'muz']);
console.log(fruits.has('elma'));   // true
console.log(fruits.has('çilek'));  // false
fruits.add('çilek');
console.log(fruits.has('çilek'));  // trueSet öğeleri üzerinde döngü yapmak için forEach() metodunu veya for...of döngüsünü kullanabilirsiniz.
const colors = new Set(['kırmızı', 'mavi', 'yeşil']);
// forEach ile iterasyon
colors.forEach(color => {
    console.log(color);
});
// Çıktı:
// kırmızı
// mavi
// yeşil
// for...of ile iterasyon
for (const color of colors) {
    console.log(color);
}
// Çıktı:
// kırmızı
// mavi
// yeşilDeğer Karşılaştırması: Setler, değerleri karşılaştırırken aynı algoritmayı kullanır. Bu, NaN değerlerinin Set içinde benzersiz olarak ele alındığı anlamına gelir (NaN === NaN false olmasına rağmen, Set içinde sadece bir adet NaN bulunabilir). Obje referansları için, farklı referanslara sahip aynı içeriğe sahip objeler farklı kabul edilir.
Sırasız Yapı: Setler, öğeleri eklenme sırasına göre depolasa da, Setin birincil amacı benzersiz öğeleri tutmaktır, belirli bir sırayı garanti etmek değildir. Bazı durumlarda iterasyon sırası ekleme sırasına denk gelebilir, ancak buna güvenilmemelidir.
Performans: Bir öğenin Set'te varlığını kontrol etmek (has() metodu) genellikle O(1) zaman karmaşıklığına sahiptir, bu da büyük veri kümeleri için dizilerdeki aramalara göre daha verimli olabilir.
Zayıf Referanslar: Eğer objeler için zayıf referanslara ihtiyacınız varsa (yani objeye başka referans kalmadığında otomatik olarak belleğin serbest bırakılmasını istiyorsanız), WeakSet kullanmanız gerekebilir. Ancak WeakSet sadece objeleri depolayabilir ve iterable değildir.
Anahtar-Değer Çiftleri İçin Setler: Eğer benzersiz anahtar-değer çiftleri depolamanız gerekiyorsa, Map nesnesi daha uygun bir seçenek olabilir.
                            JavaScript, web geliştirmede dinamik ve etkileşimli deneyimler oluşturmak için vazgeçilmez bir dildir. Bu dilin temel yapı taşlarından biri olan diziler (arrays), birden çok değeri tek bir değişken altında depolamamızı ve yönetmemizi sağlar. Diziler, veri koleksiyonlarını düzenli bir şekilde saklamak, üzerlerinde döngüler yapmak ve çeşitli manipülasyonlar gerçekleştirmek için kritik öneme sahiptir. Bu makalede, JavaScript dizilerinin temel sözdizimini, öğelere erişimi, yaygın kullanılan metotları ve pratik uygulama örneklerini detaylı bir şekilde inceleyeceğiz.
JavaScript'te dizi oluşturmanın ve kullanmanın iki temel yolu vardır:
Bu, en yaygın ve önerilen yöntemdir. Köşeli parantezler [] arasına, virgülle ayrılmış olarak dizi öğeleri yazılır.
const meyveler = ["Elma", "Muz", "Portakal"];
let sayilar = [1, 2, 3, 4, 5];
const karisikDizi = ["Metin", 123, true, null, {adi: "Nesne"}];Yukarıdaki örneklerde görüldüğü gibi, bir dizi içinde farklı veri tiplerini barındırabiliriz. Diziler const, let veya var anahtar kelimeleri ile tanımlanabilir.
new Array() kurucu fonksiyonunu kullanarak da dizi oluşturulabilir. Bu yöntem daha az tercih edilse de, belirli senaryolarda kullanılabilir.
const meyveler = new Array("Elma", "Muz", "Portakal");
const bosDizi = new Array(); // Boş bir dizi oluşturur
const onElemanliDizi = new Array(10); // 10 boş öğe içeren bir dizi oluştururTek bir sayısal argümanla çağrıldığında, new Array() o boyutta boş öğeler içeren bir dizi oluşturur. Birden fazla argümanla çağrıldığında ise, bu argümanlar dizinin öğeleri haline gelir.
Dizilerdeki öğelere, sıfır tabanlı indeksleme kullanarak erişilir. Yani, ilk öğenin indeksi 0, ikincisinin 1 ve bu şekilde devam eder. Öğelere erişmek için dizi adından sonra köşeli parantez içinde indeks numarası belirtilir.
const renkler = ["Kırmızı", "Yeşil", "Mavi"];
console.log(renkler[0]); // Çıktı: Kırmızı
console.log(renkler[1]); // Çıktı: YeşilDizi öğelerini değiştirmek de benzer şekilde yapılır. İstenen indeks belirtilerek yeni bir değer atanır:
renkler[2] = "Sarı";
console.log(renkler); // Çıktı: ["Kırmızı", "Yeşil", "Sarı"]Bir dizinin toplam öğe sayısını öğrenmek için length özelliğini kullanırız:
console.log(renkler.length); // Çıktı: 3Bu örnek, bir dizi tanımlamayı ve belirli indekslerdeki öğelere nasıl erişileceğini göstermektedir.
// Bir meyve dizisi tanımlama
const meyveler = ["Elma", "Armut", "Kiraz", "Çilek"];
// Dizinin ilk elemanına erişme (indeks 0)
console.log("İlk meyve:", meyveler[0]); // Çıktı: İlk meyve: Elma
// Dizinin üçüncü elemanına erişme (indeks 2)
console.log("Üçüncü meyve:", meyveler[2]); // Çıktı: Üçüncü meyve: Kiraz
// Dizinin son elemanına erişme (length - 1)
console.log("Son meyve:", meyveler[meyveler.length - 1]); // Çıktı: Son meyve: ÇilekBu örnek, var olan bir dizi öğesinin nasıl değiştirileceğini ve dizinin sonuna/başına öğe ekleme/çıkarma işlemlerini göstermektedir.
let alisverisListesi = ["Süt", "Ekmek", "Yumurta"];
// İkinci öğeyi değiştirme (indeks 1)
alisverisListesi[1] = "Peynir";
console.log("Değişen liste:", alisverisListesi); // Çıktı: Değişen liste: ["Süt", "Peynir", "Yumurta"]
// Dizinin sonuna yeni bir öğe ekleme (push metodu)
alisverisListesi.push("Meyve Suyu");
console.log("Ekleme sonrası:", alisverisListesi); // Çıktı: Ekleme sonrası: ["Süt", "Peynir", "Yumurta", "Meyve Suyu"]
// Dizinin sonundaki öğeyi çıkarma (pop metodu)
const cikarilanOge = alisverisListesi.pop();
console.log("Çıkarılan öğe:", cikarilanOge); // Çıktı: Çıkarılan öğe: Meyve Suyu
console.log("Çıkarma sonrası:", alisverisListesi); // Çıktı: Çıkarma sonrası: ["Süt", "Peynir", "Yumurta"]
// Dizinin başına yeni bir öğe ekleme (unshift metodu)
alisverisListesi.unshift("Yoğurt");
console.log("Başına ekleme:", alisverisListesi); // Çıktı: Başına ekleme: ["Yoğurt", "Süt", "Peynir", "Yumurta"]
// Dizinin başındaki öğeyi çıkarma (shift metodu)
const cikarilanBasOge = alisverisListesi.shift();
console.log("Baştan çıkarılan öğe:", cikarilanBasOge); // Çıktı: Baştan çıkarılan öğe: Yoğurt
console.log("Baştan çıkarma sonrası:", alisverisListesi); // Çıktı: Baştan çıkarma sonrası: ["Süt", "Peynir", "Yumurta"]Dizi öğeleri üzerinde işlem yapmak için döngüler sıkça kullanılır. En yaygın yöntemlerden biri for döngüsü ve forEach() metodudur.
const ogrenciler = ["Ali", "Ayşe", "Mehmet", "Fatma"];
// For döngüsü ile dizi öğelerini listeleme
console.log("For döngüsü ile öğrenciler:");
for (let i = 0; i < ogrenciler.length; i++) {
  console.log(ogrenciler[i]);
}
// forEach() metodu ile dizi öğelerini listeleme
console.log("\nforEach() ile öğrenciler:");
ogrenciler.forEach(function(ogrenci, index) {
  console.log(`${index + 1}. ${ogrenci}`);
});Dinamik Boyut: JavaScript dizileri dinamik yapıdadır. Oluşturulduktan sonra boyutları otomatik olarak büyüyüp küçülebilir. Önceden bir boyut belirtme zorunluluğu yoktur.
Karışık Veri Tipleri: JavaScript dizileri, aynı anda string, number, boolean, object, null, undefined gibi farklı veri tiplerini barındırabilir.
Referans Tipi: Diziler birer referans tipi (reference type) veri yapısıdır. Bir diziyi başka bir değişkene atadığınızda, aslında dizinin kendisi değil, bellekteki referansı kopyalanır. Bu nedenle, yeni değişken üzerinden yapılan değişiklikler orijinal diziyi de etkiler.
const ile Dizi Tanımlama: const ile tanımlanan bir dizinin referansı değiştirilemez, yani başka bir dizi atanması mümkün değildir. Ancak, dizinin içindeki öğeler (indeksler üzerinden) değiştirilebilir veya dizi metotları (push, pop vb.) ile manipüle edilebilir.
const sabitDizi = [1, 2, 3];
sabitDizi.push(4); // Geçerli: [1, 2, 3, 4]
// sabitDizi = [5, 6]; // Hata: Assignment to constant variable.Dizi Metotları: JavaScript, dizilerle çalışmayı kolaylaştıran zengin bir dizi metotları setine sahiptir (map(), filter(), reduce(), find(), splice(), slice() vb.). Bu metotlar, diziler üzerinde daha gelişmiş işlemler yapmak için kullanılır ve modern JavaScript programlamasında kritik öneme sahiptir.
2025 © Tüm Hakları Saklıdır.