Modülerlik ve Kod Organizasyonu Terimler Sözlüğü Modularity and Code Organization Glossary

Bu bölümde ki terimleri ezberlemenize gerek yoktur.
Konular içerisinde ki terimlerdir, sadece konuyu daha iyi anlamanıza yardımcı olması için eklenmiştir.

ES Modülleri (ESM)

ECMAScript 2015 (ES6) ile gelen resmi modül sistemi. import ve export anahtar kelimeleriyle çalışır. Statik analiz ve tree shaking desteği sağlar.

Named Export

Bir modülden birden fazla üyeyi isimleriyle dışa aktarma yöntemi. İçe aktarılırken süslü parantezlerle kullanılır:
import { topla, PI } from './math.js'

Default Export

Modül başına sadece bir tane olabilen varsayılan dışa aktarma. İçe aktarılırken süslü parantez olmadan herhangi bir isimle alınabilir.

Live Bindings

ES Modüllerinde dışa aktarılan değerlerin kopyası değil, doğrudan referansı (bağlayıcı) sağlanması. Değer güncellendiğinde tüm import eden modüller anında görür.

Bağımlılık Enjeksiyonu (DI)

Bir bileşenin ihtiyaç duyduğu bağımlılıkları kendi içinde oluşturmak yerine, dışarıdan sağlanması prensibi. Gevşek bağlılık ve test edilebilirlik sağlar.

Constructor Injection

Bağımlılıkların sınıfın constructor metoduna parametre olarak geçirilmesi. En yaygın ve güvenli DI yöntemidir.

IoC (Inversion of Control)

Kontrolün tersine çevrilmesi. Bir bileşenin bağımlılıklarını yaratma kontrolünün dışarıdaki bir yapıya (DI Konteyneri) devredilmesi.

DI Konteyneri

Bağımlılıkların kaydını, çözümlemesini ve yaşam döngüsünü yöneten merkezi yapı. Karmaşık bağımlılık grafiklerini otomatik çözer.

Gevşek Bağlılık (Loose Coupling)

Modüller arasındaki sıkı ilişkilerin gevşetilmesi. Bir modül, kullandığı bağımlılığın somut sınıfını bilmek yerine sadece arayüzünü bilir.

Sıkı Bağlılık (Tight Coupling)

Modüller arasında güçlü bağımlılıkların olması. Bir modül değiştiğinde diğer modüllerin de değişmesi gerekir. Bakım maliyeti yüksektir.

CommonJS

Node.js için tasarlanmış modül sistemi. require() ve module.exports kullanır. Senkron yükleme yapar.

AMD (Asynchronous Module Definition)

Tarayıcılar için tasarlanmış asenkron modül sistemi. define() ve require() kullanır. Non-blocking yükleme sağlar.

IIFE

Immediately Invoked Function Expression. Tanımlandığı anda hemen çalışan fonksiyon ifadesi. Kapsam izolasyonu sağlar ve global kirliliği önler.

Module Pattern

IIFE kullanarak public/private kapsülleme sağlayan desen. Closure ile iç durumu korur ve kontrollü bir API sunar.

Revealing Module Pattern

Module Pattern'in bir varyasyonu. Tüm fonksiyonlar önce tanımlanır, sonra döndürülen nesnede sadece referansları açığa çıkarılır.

Tree Shaking

Kullanılmayan kodu (dead code) nihai paketten çıkarma optimizasyonu. Statik analiz gerektirir, ES Modülleri ile mümkündür.

Statik Analiz

Kodun çalıştırılmadan önce analiz edilmesi. ES Modüllerinde import/export ifadeleri dosyanın en üst seviyesinde olmalıdır, bu sayede statik analiz mümkündür.

Namespace

İsim çakışmalarını önlemek için kullanılan isim alanı.
ES Modüllerinde import * as Modul from './modul.js' ile namespace import yapılabilir.

Encapsulation (Kapsülleme)

Veri ve işlevlerin bir arada tutulması ve dış dünyadan gizlenmesi. Module Pattern ve ES Modülleri ile sağlanır.

Dependency Graph

Modüller arasındaki bağımlılık ilişkilerinin oluşturduğu grafik yapısı. DI Konteynerleri bu grafiği otomatik çözer.

Singleton

Uygulama genelinde yalnızca tek bir örneğin oluşturulduğu yaşam döngüsü. DI Konteynerlerinde veritabanı bağlantıları için kullanılır.

Transient

Her talep edildiğinde yeni bir örneğin oluşturulduğu yaşam döngüsü. DI Konteynerlerinde geçici nesneler için kullanılır.

Scope (Kapsam)

Değişkenlerin ve fonksiyonların erişilebilir olduğu alan. JavaScript'te function scope ve block scope vardır. Modüller kendi scope'larını oluşturur.

Modüler Programlama ve Kod Organizasyonu ( Ana Konu Giriş )

Temel Söz Dizimi ve Mekanizma

ES Modüllerinin (ESM) statik yükleme modelini, Canlı Bağlayıcılar (Live Bindings) özelliğini ve CommonJS ile AMD'nin sorunlarını çözen deklaratif yapısını detaylıca inceleyin.

Ana Konu Felsefi ve Tarihsel Açıklama
Seviye 5

ES Modülleri (ESM - ECMAScript Modules) Modern Standart

Mimari Standart: Dilin Doğal Modül Sistemi

ES Modülleri (ESM), ECMAScript 2015 ile hayatımıza giren ve JavaScript'in parçalı kod yönetimini dilin çekirdeğine entegre eden resmi standarttır.

ESM öncesinde kullanılan CommonJS veya AMD gibi yapılar, dile dışarıdan eklenen çözümlerken; ESM, JavaScript'in doğal bir parçası olarak hem tarayıcı hem de sunucu ortamlarında evrensel bir dil birliği sağlar.

Statik Analiz ve Performans Devrimi

ESM'nin mimari düzeyde getirdiği en büyük yenilik Statik Yapı sunmasıdır.

CommonJS gibi sistemler çalışma anında modülleri yüklerken, ESM kod daha çalışmaya başlamadan ( parsing aşamasında ) hangi modülün neye ihtiyaç duyduğunu belirleyebilir.

Tree Shaking (Ölü Kod Ayıklama): Statik analiz sayesinde modern araçlar ( Webpack, Vite, Rollup ), projenizde kullanılmayan kod parçalarını tespit edip paketleme sırasında dışarıda bırakabilir.

Bu, web uygulamalarının boyutunu radikal şekilde küçülten ve performansı artıran bir mühendislik kazancıdır.

Ölçeklenebilirlik ve Kurumsal Hazırlık

ES Modülleri, JavaScript'in "küçük işler" için kullanılan bir dil imajını yıkarak, binlerce dosyadan oluşan kurumsal yazılımları yönetilebilir hale getirmiştir.

Modül yönetimi artık geliştiricinin manuel olarak çözmesi gereken bir karmaşa değil, dilin çekirdeğinin sunduğu bir yapısal garantidir.

Gevşek Bağlılık (Loose Coupling): Her modül kendi kapsamına (scope) sahiptir; yani bir modüldeki değişkenler, açıkça dışa aktarılmadığı ( export ) sürece global kapsamı kirletmez.

Bu izolasyon, büyük ekiplerin birbirinin kodunu bozmadan aynı proje üzerinde çalışmasını sağlar.

Sonuç: Geleceğin Kod Organizasyonu

Sonuç olarak ES Modülleri; JavaScript ekosistemini standartlaştıran, performansı matematiksel bir kesinlikle optimize eden ve modern frontend/backend mimarilerinin üzerine inşa edildiği vazgeçilmez temel taşıdır.

Çalışma Zamanı Yerine Derleme Zamanı Felsefesi Genel Bilgi

Felsefi Üstünlük: Statik Analizin Gücü

ESM'nin temel felsefesi, modül bağımlılıklarını kodun çalıştırıldığı saniyede değil, henüz hazırlık aşamasındayken belirlemektir.

Bu yaklaşım, JavaScript'in modern araçlarla ( Vite , Webpack ,Rollup ) mükemmel bir uyum yakalamasını sağlar.

Yapısal Disiplin: ESM, import ve export ifadelerinin sadece dosyanın en üst seviyesinde kullanılması kuralını zorunlu kılar.

Bu sayede tarayıcı veya sunucu, kodu satır satır çalıştırmadan önce tüm uygulama haritasını ( dependency tree ) çıkarabilir.

Performansın Anahtarı: Tree Shaking

Statik analiz yeteneği, Tree Shaking ( Ölü Kod Ayıklama ) teknolojisini mümkün kılar.

Araçlar, bir modülden dışa aktarılan ancak hiçbir yerde çağrılmayan fonksiyonları kesin olarak tespit eder.

Verimlilik: CommonJS'in dinamik yapısı nedeniyle başaramadığı bu işlem, ESM sayesinde devasa kütüphanelerin sadece ihtiyacınız olan küçük bir parçasını nihai pakete dahil etmenize olanak tanır, bu, uygulamanın dosya boyutunu küçültür ve yükleme hızını artırır.

Canlı Bağlayıcılar (Live Bindings) Mekanizması

ESM, veriyi taşıma biçimiyle de benzersizdir. CommonJS verinin o anki bir kopyasını ( value copy ) verirken; ESM, dışa aktarılan değişkene doğrudan bir referans sağlar.

Anlık Güncellik: Eğer ana modül içindeki bir değişkenin değeri değişirse, onu içe aktaran tüm modüller bu değişikliği anında görür.

Bu "canlı bağlantı", modüller arası veri tutarlılığını garanti altına alan sofistike bir mühendislik çözümüdür.

Asenkron Doğa ve Evrensel Standart

Bloke Etmeyen Yükleme: Tarayıcılar, <script type="module"> etiketini gördüklerinde bağımlılıkları paralel olarak indirirler. Bu süreçte ana sayfanın render edilmesi durmaz.

Bu asenkron yapı, kullanıcı deneyimini klasik senkron yükleme yöntemlerinden çok daha akıcı hale getirir.

Sonuç olarak ESM; statik yapısı, akıllı paketleme avantajları ve canlı veri bağlantılarıyla, JavaScript ekosistemini öngörülebilir, hızlı ve evrensel bir zemine taşımıştır.

ES Modülleri Temel Söz Dizimi Dışa ve İçe Aktarma Mekanizmaları
Kullanım
Söz Dizimi
Açıklama
İsimli Dışa Aktarma
export const PI = 3.14;

export function topla() {...}
Bir modülden birden fazla üyeyi dışarı açar.
İçe aktarılırken süslü parantezlerle isimleriyle çağrılmalıdır.
Dışa Aktarma
( Varsayılan )
export default function Hesapla() {...}
Modül başına sadece bir tane olabilir.
İçe aktarılırken süslü parantez olmadan herhangi bir isimle çağrılabilir.
İsimli İçe Aktarma
import { topla, PI } from './math.js';
Başka bir modülden belirli üyeleri isimleriyle içeri alır.
İçe Aktarma
( Varsayılan )
import Hesapla from './hesapla.js';
Varsayılan olarak dışa aktarılan üyeyi içeri alır.
Toplu İçe Aktarma
import * as Matematik from './math.js';
Tüm dışa aktarılan üyeleri bir nesne (Matematik) altına toplar.
</>
Davranış Genişletme ve Mantıksal Kontrol Örneği
Editörde Aç
<!DOCTYPE html>
<html lang="tr">

<head>
    <meta charset="UTF-8">
    <title>Yetki Kontrol</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="status" id="durum"></div>

    <script src="kontrol.js?v=1.0.150"></script>

</body>

</html>
body {
  background: #111827;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  font-family: monospace;
}

.status {
  padding: 20px 30px;
  border-radius: 6px;
  background: #22c55e;
  color: black;
}
class Kontrolcu {
  constructor(aktif) {
    this.aktif = aktif;
  }

  calistirilabilirMi() {
    return this.aktif;
  }
}

class YoneticiKontrolcusu extends Kontrolcu {
  constructor(aktif, rol) {
    super(aktif);
    this.rol = rol;
  }

  calistirilabilirMi() {
    if (!super.calistirilabilirMi()) return false;
    return this.rol === "ADMIN";
  }
}

const admin = new YoneticiKontrolcusu(true, "ADMIN");

document.getElementById("durum").textContent =
  admin.calistirilabilirMi()
    ? "✔ Erişim Onaylandı"
    : "✖ Erişim Reddedildi";
</>
ES Modules ile Modüler Kod Yapısı ( Named, Default, Namespace Import )
Editörde Aç
<!DOCTYPE html>
<html lang="tr">

<head>
    <meta charset="UTF-8" />
    <title>ES Module Örneği</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css?v=1.0.150" />
</head>

<body>

    <main class="container">
        <h1>Modüler JavaScript</h1>
        <p class="subtitle">ES Modules – Import Türleri</p>

        <div class="box">
            <h3>Çıktılar</h3>
            <pre id="cikti"></pre>
        </div>
    </main>

    <script type="module" src="app.js?v=1.0.150"></script>
</body>

</html>
:root {
    --bg: #0f172a;
    --card: #1e293b;
    --text: #e5e7eb;
    --accent: #38bdf8;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: system-ui, -apple-system, BlinkMacSystemFont;
}

.container {
    max-width: 700px;
    margin: 80px auto;
    padding: 30px;
}

h1 {
    margin-bottom: 5px;
}

.subtitle {
    color: #94a3b8;
    margin-bottom: 30px;
}

.box {
    background: var(--card);
    border-radius: 12px;
    padding: 20px;
    border-left: 4px solid var(--accent);
}

pre {
    background: #020617;
    padding: 15px;
    border-radius: 8px;
    overflow-x: auto;
    font-size: 14px;
}
// Named export
export function veriIsle(veri) {
  return veri.toUpperCase();
}

// Named export
export const VERSIYON = "1.2.0";

// Default export
export default {
  url: "local",
  timeout: 3000,
};
// 1. İsimli Üyeleri İçe Aktarma
import { veriIsle, VERSIYON } from "./modul.js";

// 2. Varsayılan Üyeyi İçe Aktarma
import baglanti from "./modul.js";

// 3. Toplu (Namespace) İçe Aktarma
import * as Modul from "./modul.js";

const cikti = `
veriIsle("test verisi"):
${veriIsle("test verisi")}

VERSIYON:
${VERSIYON}

Default Export (baglanti.url):
${baglanti.url}

Namespace Import (Modul.VERSIYON):
${Modul.VERSIYON}
`;

document.getElementById("cikti").textContent = cikti;
</>
Canlı Bağlayıcılar (Live Bindings) – Paylaşılan Durum Yönetimi
Editörde Aç
<!DOCTYPE html>
<html lang="tr">

<head>
    <meta charset="UTF-8" />
    <title>ES Modules – Live Bindings</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css?v=1.0.150" />
</head>

<body>

    <main class="wrapper">
        <header>
            <h1>Canlı Bağlayıcılar</h1>
            <p>ES Modules – Live Bindings (Paylaşılan Referans)</p>
        </header>

        <section class="card">
            <div class="info">
                <span class="label">Paylaşılan Sayaç</span>
                <strong id="sayacDegeri">0</strong>
            </div>

            <button id="artirBtn">Sayaç Artır</button>

            <p class="note">
                Bu değer başka bir modül içinde güncellenir ve
                <strong>canlı referans</strong> sayesinde burada anında değişir.
            </p>
        </section>
    </main>

    <script type="module" src="canli-kullanim.js?v=1.0.150"></script>
</body>

</html>
:root {
    --bg: #020617;
    --panel: #020617;
    --card: #020617;
    --border: #1e293b;
    --text: #e5e7eb;
    --muted: #94a3b8;
    --accent: #22d3ee;
    --accent-soft: rgba(34, 211, 238, 0.15);
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    min-height: 100vh;
    background:
        radial-gradient(circle at top, #020617, #020617);
    color: var(--text);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Ana alan */
.wrapper {
    width: 100%;
    max-width: 520px;
    padding: 24px;
}

/* Başlık */
header {
    margin-bottom: 24px;
}

h1 {
    font-size: 26px;
    margin-bottom: 6px;
}

header p {
    color: var(--muted);
    font-size: 14px;
}

/* Kart */
.card {
    background: linear-gradient(180deg,
            #020617,
            #020617);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 24px;
    box-shadow:
        0 20px 40px rgba(0, 0, 0, 0.45);
}

/* Sayaç Alanı */
.info {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 20px;
}

.label {
    font-size: 13px;
    color: var(--muted);
}

.info strong {
    font-size: 32px;
    color: var(--accent);
}

/* Buton */
button {
    width: 100%;
    padding: 12px;
    font-size: 15px;
    font-weight: 600;
    border-radius: 10px;
    border: none;
    cursor: pointer;
    background: linear-gradient(135deg,
            var(--accent),
            #38bdf8);
    color: #020617;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

button:hover {
    transform: translateY(-1px);
    box-shadow: 0 10px 25px var(--accent-soft);
}

/* Açıklama */
.note {
    margin-top: 16px;
    font-size: 13px;
    color: var(--muted);
    line-height: 1.5;
}
// sayac-kaynak.js

export let sayac = 0; // Canlı referans dışa aktarılıyor

export function artir() {
  sayac++;
  console.log(`[Kaynak] Sayaç güncellendi: ${sayac}`);
}
// canli-kullanim.js

import { sayac, artir } from "./sayac-kaynak.js";

const sayacEl = document.getElementById("sayacDegeri");
const btn = document.getElementById("artirBtn");

// İlk değer
console.log("Başlangıç:", sayac);
sayacEl.textContent = sayac;

// Buton ile canlı güncelleme
btn.addEventListener("click", () => {
  artir(); // Kaynak modülde değişir
  sayacEl.textContent = sayac; // Canlı bağlayıcı sayesinde güncel
  console.log("Artış Sonrası:", sayac);
});

// ❌ Bu mümkün değildir
// sayac = 99; // Syntax Error (read-only import)
Seviye 6

Bağımlılık Enjeksiyonu (DI) Mimaride Esneklik

Temel Prensip: Bağımlılıkları Dışarıdan Almak

Bağımlılık Enjeksiyonu (DI), modern yazılım mimarisinin en temel ve güçlü prensiplerinden biridir.

Bir bileşenin ihtiyaç duyduğu yardımcı araçları ( servisler., veri tabanı bağlantıları , loglama araçları vb. ) kendi içinde new anahtar kelimesiyle oluşturmak yerine, bu bağımlılıkların o bileşene dışarıdan enjekte edilmesi anlamına gelir.

Felsefi Temel: Kontrolün Tersine Çevrilmesi (IoC)

DI'nın kalbinde Kontrolün Tersine Çevrilmesi yatar.

Geleneksel yöntemde bir sınıf, bağımlı olduğu servisi yaratma ve yönetme kontrolüne bizzat sahiptir.

Ancak DI modelinde bu kontrol, sınıftan alınarak dışarıdaki bir yapıya ( bir DI Konteyneri veya çağıran üst kod ) devredilir.

Gevşek Bağlılık (Loose Coupling): Bu yer değiştirme sayesinde Modül A, Modül B'nin nasıl inşa edildiğini veya hangi detaylara sahip olduğunu bilmek zorunda kalmaz.

Sadece Modül B'nin işlevine odaklanır; bu da sistemin parçaları arasındaki sıkı bağı kopararak esneklik sağlar.

Mimari Kazanç: Test Edilebilirlik ve İzolasyon

DI'nın en somut avantajı Birim Test süreçlerinde görülür.

Bir bileşeni test ederken, onun gerçek ve ağır bağımlılıkları ( gerçek bir veritabanı veya canlı ödeme sistemi gibi ) yerine, dışarıdan sahte

( Mock/Stub ) servisler enjekte edebilirsiniz.

Örneğin: Gerçek bir LoglamaServisi yerine, test anında sadece verileri bellekte tutan bir TestLoglamaServisi enjekte ederek, bileşenin mantığını dış dünyadan tamamen izole bir şekilde, hızlı ve güvenilirce test edebilirsiniz.

Sonuç: Ölçeklenebilir ve Bakımı Kolay Kod

Özet olarak Bağımlılık Enjeksiyonu; kodu katı ve kırılgan bir yapıdan kurtarıp, parçaları kolayca değiştirilebilen modüler ve profesyonel bir sisteme dönüştürür ve özellikle büyük ölçekli uygulamalarda, yönetilebilirliğin anahtarı bu prensiptir.

DI'nın Temel Avantajları Genel Bilgi

1. Test Edilebilirlik (Testability) ve İzolasyon

DI'nın en doğrudan avantajı, kodun birim testler için tamamen hazır hale gelmesidir.

Bir bileşen, bağımlılıklarını dışarıdan aldığı için, test aşamasında bu bileşene "gerçek" servisler yerine "sahte" nesneler enjekte edilebilir.

Güvenli Alan: Örneğin, bir ödeme modülünü test ederken gerçek banka API'sine bağlanmak yerine, her zaman başarılı sonuç dönen sahte bir servis enjekte ederek sadece kendi kodunuzun doğruluğunu izole bir ortamda kanıtlayabilirsiniz.

2. Gevşek Bağlılık ve Esneklik (Loose Coupling)

Geleneksel yapılarda bir bileşeni değiştirmek, ona bağlı olan tüm sistemi etkileyebilir.

DI ile bileşenler arasındaki sıkı bağlar çözülür.

Bileşenler artık somut sınıflara değil, soyut arayüzlere ( Interface / Abstraction ) bağımlı hale gelir.

Teknoloji Bağımsızlığı: Yarın bir gün veri tabanı sağlayıcınızı veya loglama kütüphanenizi değiştirmek isterseniz, uygulamanın çekirdek koduna dokunmadan sadece dışarıdan enjekte edilen servisi değiştirmeniz yeterli olur.

Bu, sisteme çeviklik ( Agility ) kazandırır.

3. Bakım Kolaylığı ve Yeniden Kullanılabilirlik

Sorumlulukların Ayrılması (SoC): DI, bir bileşenin sadece kendi işine odaklanmasını sağlar; bağımlılıkları "nasıl yaratacağı" konusu o bileşenin sorunu olmaktan çıkar, bu durum, kodun daha temiz, okunabilir ve dolayısıyla bakımı kolay bir yapıya bürünmesini sağlar.

Modüler Parçalar: Bağımlılıklarını dışarıdan bekleyen bir bileşen, farklı projelerde veya uygulamanın farklı bölümlerinde, o ortama uygun bağımlılıklarla tekrar tekrar kullanılabilir böylece kod tekrarı azalırken, geliştirme hızı katlanarak artar.

Sonuç: Geleceğe Hazır Yazılım

Sonuç olarak DI; yazılımı tek parça ve kırılgan bir blok olmaktan çıkarıp, her bir parçası bağımsızca geliştirilebilen, test edilebilen ve değiştirilebilen

profesyonel bir mühendislik harikasına dönüştürür.

Test Edilebilirlik (Testability) Test Edilebilirlik Nedir?

Geleneksel Engel: Sıkı Bağlılık ve Test Zorluğu,

Test Edilebilirlik, bir yazılım bileşeninin beklenen işlevleri yerine getirip getirmediğini ne kadar kolay ve güvenilir bir şekilde doğrulayabildiğimizin ölçüsüdür.

Geleneksel yapılarda bir sınıf, bağımlı olduğu servisi ( new VeritabaniServisi() gibi ) kendi içinde oluşturduğunda, o sınıf "dış dünyaya" göbekten bağlı hale gelir.

Bağımlılık Tuzağı: Bu durumda, sadece basit bir iş mantığını test etmek için bile gerçek bir veritabanı kurulumuna, aktif bir ağ bağlantısına veya karmaşık konfigürasyonlara ihtiyaç duyarsınız.

Bu, testlerin hem yavaşlamasına hem de dış etkenler nedeniyle sık sık başarısız olmasına yol açar.

DI ile İzole Test Ortamı: Mock ve Stub Kavramları

Bağımlılık Enjeksiyonu, bu düğümü İzolasyon ile çözer.

Bileşen, ihtiyacı olan servisi dışarıdan beklediği için, test anında ona gerçek servis yerine bu servisin bir "dublörünü" verebiliriz.

Taklit (Mocking) Stratejisi: Bir API çağrısı yapan modülü test ederken gerçek internete çıkmak yerine, önceden belirlenmiş yanıtları ( success veya error ) saniyeler içinde dönen bir SahteApiServisi enjekte edebiliriz, bu sayede test sadece o modülün API'den gelen cevabı doğru işleyip işlemediğine odaklanır.

Hız, Güvenilirlik ve Deterministik Sonuçlar

Hızlı Geri Bildirim: DI ile yazılan testler milisaniyeler içinde tamamlanır; çünkü ağır dış sistemleri başlatmak zorunda kalmazsınız.

Geliştirici, yazdığı kodun doğruluğunu anında teyit edebilir.

Deterministik Testler: Test sonuçları "hava durumuna" veya "ağ yavaşlığına" göre değişmez.

Her çalıştırıldığında aynı girdiye aynı çıktıyı verir.

Bu istikrar, uygulamanın Güvenilirlik AQC'sini ( Nitelik Gereksinimi ) en üst düzeye çıkarır.

Sonuç: Odaklanmış Doğrulama

Test Edilebilirlik; DI sayesinde yazılımın her bir parçasını birer laboratuvar ortamındaymışçasına, dış dünyadan izole ve kusursuz bir kesinlikle doğrulayabilme yeteneğidir.

Gevşek Bağlılık (Loose Coupling) ve Değişim Esnekliği Gevşek Bağlılık Nedir?

Gevşek Bağlılık: Sıkı Bağları Çözmek

Gevşek Bağlılık, bir yazılım sistemindeki modüllerin birbirlerinin iç detaylarına ve somut kimliklerine olan aşırı bağımlılığını ortadan kaldırma sanatıdır.

DI, modüller arasındaki bu "göbekten bağı" gevşeterek, sistemin bir parçasında yapılan değişikliğin diğer parçaları sarsmasını engeller.

Sınıf Bilgisinin Ötesi: Soyutlama ve Arayüzler

Somut Sınıf Hapishanesi: Geleneksel programlamada, bir fonksiyonun içinde const logger = new ConsoleLogger() yazmak, o kodu sonsuza dek ConsoleLogger sınıfına mahkum eder.

Yarın bir gün logları konsol yerine bir dosyaya yazmak istediğinizde, projedeki tüm bu "new" satırlarını tek tek bulup değiştirmeniz gerekir.

Arayüz Odaklılık: DI ile bileşen, kullandığı aracın "kim" ( somut sınıf ) olduğuyla değil, "ne yapabildiği" ( soyut arayüz / metodlar ) ile ilgilenir.

Bileşen sadece log() metodunun varlığını bilir; bu metodun arkasında hangi sınıfın çalıştığını bilmesi gerekmez.

Merkezi Değişim ve Düşük Bakım Maliyeti

Esnek Yer Değiştirme: DI sayesinde, bir bağımlılığı değiştirmek çocuk oyuncağına dönüşür.

Örneğin: ConsoleLogger yerine FileLogger kullanmaya karar verdiğinizde, bu değişikliği onu kullanan yüzlerce bileşende değil, sadece bağımlılıkların enjekte edildiği tek bir merkezi noktada yaparsınız.

Bakım Kolaylığı: Bu yapısal esneklik, büyük ölçekli projelerde "refactoring" ( kodu iyileştirme ) süreçlerini hızlandırır ve hata riskini minimize eder.

Sistemin parçaları birbirinden bağımsızlaştıkça, projenin Sürdürülebilirlik AQC'si en üst seviyeye çıkar.

Yeniden Kullanılabilirlik (Reusability) Genel Bilgi

Modüler Taşınabilirlik: Kodun Özgürleşmesi

Yeniden Kullanılabilirlik, bir bileşenin yazıldığı ilk bağlamdan koparılıp, farklı ortamlarda ve senaryolarda sorunsuzca çalıştırılabilme yeteneğidir.

DI, bir modülün bağımlılıklarını kendisinin yaratma zorunluluğunu ortadan kaldırarak, o modülün taşınabilirliğini doğrudan en üst seviyeye çıkarır.

Bağlamdan Bağımsız İş Mantığı

Soyutlanmış Çekirdek: DI sayesinde, uygulamanın ana iş mantığını yürüten sınıflar ( SiparisIsleyici gibi ), yan hizmetlerin ( ödeme, bildirim, loglama ) somut detaylarından tamamen arındırılır.

Bu sınıflar artık "bir veritabanına nasıl bağlanılacağını" değil, sadece "siparişin nasıl işleneceğini" bilirler.

Çoklu Ortam Desteği: Bu izolasyon, aynı temel iş mantığının bir mobil uygulamada, bir web sunucusunda veya bir masaüstü yazılımında

hiç değiştirilmeden kullanılmasını sağlar.

Kod sabit kalır; sadece o ortama uygun olan bağımlılıklar dışarıdan enjekte edilir.

Farklı Konfigürasyonlarla Dinamik Adaptasyon

Bir modülün yeniden kullanılabilirliği, sadece farklı projelerde değil, aynı projenin farklı yaşam evrelerinde de kritik rol oynar:

Geliştirme / Test Aşaması: Bir BildirimServisi kullanılırken, sistem maliyet yaratmamak için sadece konsola çıktı veren bir TestBildirimci ile yapılandırılabilir.

Canlı (Production) Aşaması: Aynı modül, hiçbir kod değişikliği yapılmadan, gerçek dünya SMS veya E-posta API'lerine bağlanan profesyonel bir SMSBildirimci ile canlıya alınabilir.

Sonuç: Akıllı Kod Yönetimi

Yeniden kullanım, sadece kodu kopyalayıp yapıştırmak değildir; aynı kodun farklı davranışlarla tekrar tekrar çalıştırılabilmesidir.

Bu esneklik, üçüncü taraf bir servisten ( farklı bir ödeme altyapısı gibi ) vazgeçildiğinde veya yeni bir platforma geçildiğinde uygulamanın değişime karşı direncini artırır.

Sonuç olarak Yeniden Kullanılabilirlik; DI sayesinde kodun "katı" bir yapıdan kurtulup, her türlü ihtiyaca cevap verebilen evrensel bir yapı taşına dönüşmesidir.

Sıkı ve Gevşek Bağlılık Karşılaştırması Bağımlılık Enjeksiyonu (DI) Etkisi
Kriter
Sıkı Bağlılık (Tight Coupling - DI Yok)
Gevşek Bağlılık (Loose Coupling - DI Var)
Loglama
class Rapor {
  constructor() {
    this.log = new ConsoleLogger();
  }
}
class Rapor {
  constructor(logger) {
    this.log = logger;
  }
}
Değişim Maliyeti
Logger'ı değiştirmek için Rapor sınıfının içini değiştirmek zorunludur.
Logger'ı değiştirmek için sadece Rapor sınıfını çağıran kodu değiştirmek yeterlidir.
Test Edilebilirlik
Dışarıdan müdahale edilemez, Logger her zaman gerçektir.
Test anında, Logger yerine sahte (mock) bir obje enjekte edilebilir.

JavaScript'te DI Uygulama Yolları Genel Bilgi

Esnek Mimari: İhtiyaca Göre Enjeksiyon

JavaScript'te DI Uygulama Yolları, dilin dinamik yapısı sayesinde projenin ölçeğine ve teknik gereksinimlerine göre çeşitlilik gösterir.

Bir bağımlılığın sınıfa ne zaman ve nasıl dahil edileceği, o sistemin test edilebilirliğini ve sürdürülebilirliğini doğrudan belirler.

1. Yapıcı (Constructor) Enjeksiyonu

Zorunlu Bağımlılıklar: En yaygın kullanılan yöntemdir.

Bağımlılıklar, sınıfın constructor metoduna parametre olarak gönderilir.

Bu yöntem, sınıfın çalışması için o bağımlılığın olmazsa olmaz olduğunu garanti eder.

Nesne yaratıldığı an tüm araçları elindedir.

2. Özellik/Metot (Setter) Enjeksiyonu

İsteğe Bağlı Bağımlılıklar: Nesne oluşturulduktan sonra, belirli bir metot ( setService() gibi ) aracılığıyla bağımlılığın aktarılmasıdır.

Bağımlılık her zaman gerekli değilse veya çalışma anında değiştirilmesi gerekiyorsa bu yöntem tercih edilir.

Esneklik sağlar ancak bağımlılık gelmeden metot çağrılırsa hata alma riski taşır.

3. Parametre Enjeksiyonu (Fonksiyonel Yaklaşım)

JavaScript'in fonksiyonel gücünü kullanan bu yöntemde, bağımlılık doğrudan fonksiyonun bir argümanı olarak iletilir.

Sınıf tabanlı olmayan, saf fonksiyonel ( functional programming ) mimarilerde en temiz ve en kolay test edilebilir yöntemdir.

Mimari Karar: Hangi Yol Seçilmeli?

Kontrol ve Yaşam Döngüsü: Geliştirici, bağımlılıklar ile nesneler arasındaki ilişkiyi bu yöntemlerle hassas bir şekilde yönetir.

Eğer bir nesne o bağımlılık olmadan "eksik" kalacaksa Constructor; eğer bağlam değiştikçe ( testten canlıya geçiş gibi ) farklı araçlar kullanılacaksa Setter veya Parametre enjeksiyonu mimariyi kurtarır.

Özetlemek gerekirse JavaScript; katı kurallara hapsolmadan, amaca en uygun ve kod tekrarını minimize eden enjeksiyon stilini seçebilmemiz için bize geniş bir mühendislik alanı sunar.

Constructor Enjeksiyonu (Constructor Injection) Constructor Injection Nedir?

Zorlayıcı Form: Nesne Oluşum Şartı

Constructor Enjeksiyonu, Bağımlılık Enjeksiyonu'nun en yaygın ve en güvenli uygulama biçimidir.

Bu yöntemde bağımlılıklar, sınıfın örneği oluşturulduğu anda ( new Sınıf(...) ) doğrudan yapıcı metot ( constructor ) aracılığıyla birer parametre olarak içeri aktarılır.

Bu, nesnenin "doğum anında" tüm yeteneklerine sahip olmasını garanti eder.

Şeffaflık ve Kendi Kendini Belgeleme

Açık Sözleşme: Bu yöntem, bir sınıfın çalışabilmesi için hangi dış servislere ( Örn: Veritabanı, Logger, EmailServisi ) ihtiyaç duyduğunu kapalı kapılar ardında değil, sınıfın giriş kapısında ( constructor imzasında ) ilan eder.

Geliştirici Dostu: Kodu okuyan bir geliştirici, sınıfa gitmeden sadece imzasını görerek onun gereksinimlerini anlar.

Bu durum, kodun dokümantasyon ihtiyacını azaltır ve hatalı kullanımın ( eksik bağımlılıkla nesne yaratma ) önüne geçer.

Değişmezlik (Immutability) Avantajı

Yaşam Boyu Kararlılık: Constructor metodu bir sınıfın yaşam döngüsü boyunca sadece bir kez çalışır.

Bu sayede enjekte edilen bağımlılıklar, nesne hayatta olduğu sürece değiştirilemez ( read-only ) olarak tutulabilir.

Güvenli Durum: Bağımlılıkların çalışma anında kazara veya kötü niyetle değiştirilme riski ortadan kalkar.

Bu disiplinli yaklaşım, özellikle karmaşık ve büyük ölçekli uygulamalarda sistem tutarlılığını koruyan vazgeçilmez bir güvenlik katmanıdır.

Sonuç: Sağlam Temeller Üzerine İnşa

Sonuç olarak Constructor Enjeksiyonu; bir sınıfı "bağımlılıklarını aramak zorunda kalan bir avcıdan", "ihtiyaçları kendisine sunulan bir yöneticiye" dönüştürür ve bu, test edilebilirliğin ve modülerliğin en sağlam temelidir.

</>
Logger Değiştirilebilirliği ile Gevşek Bağlılık ( Loose Coupling ) Örneği
Editörde Aç
<!DOCTYPE html>
<html lang="tr">

<head>
    <meta charset="UTF-8" />
    <title>DI – Logger Değiştirilebilirliği</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css?v=1.0.150" />
</head>

<body>

    <main class="container">
        <h1>Bağımlılık Enjeksiyonu</h1>
        <p class="subtitle">Logger Değiştirilebilirliği (Loose Coupling)</p>

        <div class="card">
            <button id="btnConsole">Console Logger ile Rapor</button>
            <button id="btnPanel">Panel Logger ile Rapor</button>

            <div class="log-panel" id="logPanel">
                <strong>Panel Logger Çıktısı</strong>
            </div>
        </div>
    </main>

    <script type="module" src="app.js?v=1.0.150"></script>
</body>

</html>
:root {
    --bg: #0f172a;
    --card: #1e293b;
    --text: #e5e7eb;
    --accent: #38bdf8;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: system-ui, -apple-system, BlinkMacSystemFont;
}

.container {
    max-width: 720px;
    margin: 80px auto;
    padding: 30px;
}

h1 {
    margin-bottom: 6px;
}

.subtitle {
    color: #94a3b8;
    margin-bottom: 32px;
}

.card {
    background: var(--card);
    padding: 24px;
    border-radius: 14px;
    border-left: 5px solid var(--accent);
}

button {
    background: var(--accent);
    color: #020617;
    border: none;
    padding: 10px 16px;
    margin-right: 10px;
    border-radius: 8px;
    font-weight: 600;
    cursor: pointer;
}

button:hover {
    opacity: 0.9;
}

.log-panel {
    margin-top: 20px;
    background: #020617;
    padding: 15px;
    border-radius: 10px;
    font-size: 14px;
    min-height: 60px;
}

/* ------------------------------ */
/* Mobil Responsive Eklemeleri    */
/* ------------------------------ */
@media (max-width: 768px) {
    .container {
        margin: 40px 20px;
        padding: 20px;
    }

    h1 {
        font-size: 1.5rem;
    }

    .subtitle {
        font-size: 0.95rem;
        margin-bottom: 24px;
    }

    .card {
        padding: 18px;
        border-left-width: 4px;
    }

    button {
        padding: 8px 14px;
        margin-bottom: 8px;
        width: 100%;
        display: block;
    }

    .log-panel {
        font-size: 13px;
        padding: 12px;
        min-height: 50px;
    }
}
import { RaporServisi } from "./rapor-servisi.js";
import { ConsoleLogger, PanelLogger } from "./logger.js";

const panel = document.getElementById("logPanel");

document.getElementById("btnConsole").addEventListener("click", () => {
  const logger = new ConsoleLogger();
  const rapor = new RaporServisi(logger);
  rapor.raporOlustur();
});

document.getElementById("btnPanel").addEventListener("click", () => {
  const logger = new PanelLogger(panel);
  const rapor = new RaporServisi(logger);
  rapor.raporOlustur();
});
export class RaporServisi {
  constructor(logger) {
    this.logger = logger;
  }

  raporOlustur() {
    this.logger.log("Rapor oluşturuldu.");
  }
}
export class ConsoleLogger {
  log(message) {
    console.log(`[ConsoleLogger] ${message}`);
  }
}

export class PanelLogger {
  constructor(panelElement) {
    this.panel = panelElement;
  }

  log(message) {
    this.panel.innerHTML += `<div>${message}</div>`;
  }
}

Setter Enjeksiyonu (Setter Injection) Setter Injection Nedir?

Dinamik Yapı: Nesne Oluşumundan Sonra Müdahale

Setter Enjeksiyonu (veya Özellik Enjeksiyonu ), bağımlılıkların bir sınıf örneği hayata geçtikten sonra, genellikle setService() gibi özel metodlar aracılığıyla sisteme dahil edilmesidir.

Constructor enjeksiyonunun aksine, burada nesne "boş" veya "kısmi" olarak yaratılabilir ve yetenekleri sonradan kazandırılabilir.

İsteğe Bağlılık ve Geç Yükleme (Lazy Loading)

Esnek Gereksinimler: Bu yöntem, bir bağımlılığın "isteğe bağlı" olduğu durumlar için idealdir.

Eğer bir servis ( Gelişmiş İstatistik Servisi gibi ) her zaman kullanılmıyorsa veya sadece belirli kullanıcı aksiyonlarından sonra ihtiyaç duyulacaksa, nesneyi en baştan bu ağır bağımlılıkla yüklemek yerine Setter ile sonradan yapılandırmak performansı artırır.

Çalışma Zamanı Değişimi: Uygulama çalışırken bir stratejiden diğerine geçmek ( Runtime Swapping ) gerekebilir.

Örneğin: Ağ bağlantısı koptuğunda bir VeriServisi'ni anında CevrimdisiServis ile değiştirmek için Setter enjeksiyonu eşsiz bir kolaylık sağlar.

Riskler: Öngörülebilirlik ve Güvenlik

Durum Belirsizliği: Setter enjeksiyonunun en büyük dezavantajı, nesnenin "geçersiz bir durumda" kalma riskidir.

Eğer geliştirici gerekli olan bir setter metodunu çağırmayı unutursa ve sınıf içindeki bir fonksiyon bu bağımlılığı kullanmaya çalışırsa, uygulama null veya undefined hatalarıyla çökebilir.

Değişkenlik (Mutability): Constructor enjeksiyonunun sunduğu "değişmezlik" garantisi burada yoktur.

Bağımlılıklar objenin yaşam döngüsü boyunca istenmeyen bir anda değiştirilebilir, bu da hata ayıklama süreçlerini daha karmaşık hale getirebilir.

Sonuç: Kontrollü Esneklik

Özet olarak Setter Enjeksiyonu; zorunlu olmayan eklentiler ve dinamik strateji değişimleri için mükemmel bir araçtır.

Ancak mimaride kullanırken, nesnenin her zaman tutarlı bir durumda kalmasını sağlayacak ek kontroller ( null checks ) ile desteklenmelidir.

</>
Setter Enjeksiyonu ile Kullanıcı Ayarları ve Bildirim Sistemi Örneği
Editörde Aç
<!DOCTYPE html>
<html lang="tr">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Setter Enjeksiyonu Örneği</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="card">
        <h2>Kullanıcı Ayarları</h2>

        <label for="tema">Tema Seçin:</label>
        <select id="tema">
            <option value="light">Açık</option>
            <option value="dark">Koyu</option>
        </select>

        <button id="kaydetBtn">Ayarları Kaydet</button>

        <div class="output" id="output">Bildirimler burada görünecek...</div>
    </div>

    <script src="script.js?v=1.0.150"></script>

</body>

</html>
:root {
    --bg: #f0f4f8;
    --card-bg: #ffffff;
    --text: #1f2937;
    --accent: #3b82f6;
    --border: #e5e7eb;
    --success: #10b981;
    --warning: #f59e0b;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: 'Segoe UI', sans-serif;
    background-color: var(--bg);
    color: var(--text);
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

.card {
    background: var(--card-bg);
    padding: 2rem;
    border-radius: 12px;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
    max-width: 400px;
    width: 100%;
}

h2 {
    margin-top: 0;
    color: var(--accent);
    text-align: center;
}

label {
    display: block;
    margin-top: 1rem;
    font-weight: 600;
}

select {
    width: 100%;
    padding: 0.5rem;
    margin-top: 0.5rem;
    border-radius: 6px;
    border: 1px solid var(--border);
    font-size: 1rem;
}

button {
    width: 100%;
    padding: 0.75rem;
    margin-top: 1.5rem;
    border: none;
    border-radius: 6px;
    background-color: var(--accent);
    color: white;
    font-size: 1rem;
    cursor: pointer;
    transition: 0.2s;
}

button:hover {
    background-color: #2563eb;
}

.output {
    margin-top: 1rem;
    padding: 0.75rem;
    border-radius: 6px;
    border: 1px solid var(--border);
    min-height: 2rem;
    text-align: center;
    font-weight: 600;
}
class KullaniciAyarlari {
  constructor() {
    this.tema = "light";
    this.bildirimci = null; // Opsiyonel bağımlılık
  }

  // 💡 Setter Enjeksiyonu
  setBildirimServisi(servis) {
    this.bildirimci = servis;
  }

  ayarlariKaydet() {
    if (this.bildirimci) {
      this.bildirimci.gonder(
        `Ayarlar başarıyla kaydedildi. Tema: ${this.tema}`,
      );
    }
  }
}

// Bildirim servisi
const konsolUyariServisi = {
  gonder: (msg) => {
    const output = document.getElementById("output");
    output.textContent = msg;
    output.style.borderColor = "#10b981"; // Başarılı mesaj
  },
};

// Kullanıcı ayarları oluştur
const ayarlar = new KullaniciAyarlari();

// Setter enjeksiyonu ile servisi ekle
ayarlar.setBildirimServisi(konsolUyariServisi);

// DOM etkileşimleri
const temaSelect = document.getElementById("tema");
const kaydetBtn = document.getElementById("kaydetBtn");

temaSelect.addEventListener("change", (e) => {
  ayarlar.tema = e.target.value;
});

kaydetBtn.addEventListener("click", () => {
  ayarlar.ayarlariKaydet();
});

Fonksiyon/Metot Enjeksiyonu (Function/Method Injection) Setter Injection Nedir?

Nokta Atışı: Sadece İhtiyaç Anında Enjeksiyon

Fonksiyon/Metot Enjeksiyonu, bir bağımlılığın nesnenin kalıcı bir parçası olarak saklanması yerine, sadece o bağımlılığı kullanan spesifik bir işlem ( metot çağrısı ) sırasında argüman olarak iletilmesidir.

Bu yöntem, bağımlılığı "sınıfın malı" olmaktan çıkarıp "işlemin bir aracı" haline getirir.

Sınırlı Kapsam ve Temiz Nesne Yapısı

Geçici Gereksinimler: Bazı bağımlılıklar bir nesnenin tüm ömrü boyunca değil, sadece nadiren tetiklenen bir görev için gereklidir.

Örneğin: Bir Kullanici nesnesi her zaman bir PdfOlusturucu servisine ihtiyaç duymaz.

Bu servisi constructor'da almak yerine, sadece faturaIndir(pdfServis) metoduna enjekte etmek mimariyi çok daha temiz tutar.

İzolasyon: Bu yaklaşım sayesinde nesnenin diğer metotları ve özellikleri bu bağımlılıktan tamamen habersiz kalır.

Bu durum, "Bilmesi Gereken Kadar" ( Principle of Least Knowledge ) prensibini destekleyerek karmaşıklığı azaltır.

Avantajı: Bellek Verimliliği ve Fonksiyonel Esneklik

Kaynak Yönetimi: Bağımlılığın nesne referansı olarak sınıfta tutulmaması, özellikle bellek yönetimi açısından avantaj sağlar.

Bağımlılık sadece metot çalıştığı sürece hafızada aktif kalır, işlem bitince çöp toplayıcı ( Garbage Collector ) tarafından temizlenebilir.

Test Kolaylığı: Metot düzeyindeki enjeksiyon, birim testleri mikro düzeyde yapmamıza olanak tanır.

Nesnenin tamamını yapılandırmak yerine, sadece test etmek istediğiniz metoda sahte bir servis göndererek anında sonuç alabilirsiniz.

Sonuç: Minimalist ve Dinamik Mimari

Sonuç olarak Fonksiyon/Metot Enjeksiyonu; nesneleri ağır bağımlılık yüklerinden kurtaran, onları hafif, esnek ve görev odaklı tutan akıllı bir mimari tercihtir.

Modern JavaScript geliştirme süreçlerinde, özellikle fonksiyonel programlama yaklaşımlarıyla mükemmel uyum sağlar.

</>
Logger Değiştirilebilirliği ile Gevşek Bağlılık ( Loose Coupling ) Örneği
Editörde Aç
<!DOCTYPE html>
<html lang="tr">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fonksiyon/Metot Enjeksiyonu Örneği</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>

    <div class="card">
        <h2>Dosya İşleyici</h2>
        <label for="dosya">Dosya Yolu:</label>
        <input type="text" id="dosya" placeholder="Dosya yolunu girin...">
        <button id="isleBtn">Dosyayı İşle</button>
        <div class="output" id="output">Bildirimler burada...</div>
    </div>

    <script type="module" src="main.js?v=1.0.150"></script>

</body>

</html>
body {
    font-family: 'Segoe UI', sans-serif;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    background: #f0f4f8;
    margin: 0;
}

.card {
    background: #fff;
    padding: 2rem;
    border-radius: 12px;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
    max-width: 400px;
    width: 100%;
}

h2 {
    text-align: center;
    color: #3b82f6;
}

input {
    width: 100%;
    padding: 0.5rem;
    margin-top: 0.5rem;
    border-radius: 6px;
    border: 1px solid #e5e7eb;
}

button {
    width: 100%;
    padding: 0.75rem;
    margin-top: 1rem;
    border: none;
    border-radius: 6px;
    background: #3b82f6;
    color: white;
    cursor: pointer;
}

button:hover {
    background: #2563eb;
}

.output {
    margin-top: 1rem;
    padding: 0.75rem;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    min-height: 2rem;
    text-align: center;
    font-weight: 600;
}
// logger.js
export const hataKaydedici = {
  kaydet: (msg) => {
    const output = document.getElementById("output");
    output.textContent = `[HATA] ${msg}`;
    output.style.borderColor = "#f59e0b"; // Uyarı rengi
    console.error(`[FATAL] ${msg}`);
  },
};
// metotEnjeksiyonu.js
export class DosyaIsleyici {
  // Metot enjeksiyonu: Hata kaydedici sadece metoda argüman olarak veriliyor
  okuVeIsle(dosyaYolu, hataKaydedici) {
    if (!dosyaYolu) {
      hataKaydedici.kaydet("Dosya yolu belirtilmedi.");
      return;
    }
    // Burada dosya okuma mantığı simüle ediliyor
    const output = document.getElementById("output");
    output.textContent = `Dosya '${dosyaYolu}' başarıyla işlendi.`;
    output.style.borderColor = "#10b981"; // Başarı rengi
    console.log(`Dosya '${dosyaYolu}' işlendi.`);
  }
}
import { DosyaIsleyici } from "./metotEnjeksiyonu.js";
import { hataKaydedici } from "./logger.js";

const dosyaInput = document.getElementById("dosya");
const btn = document.getElementById("isleBtn");
const isleyici = new DosyaIsleyici();

btn.addEventListener("click", () => {
  // Metot enjeksiyonu: Hata kaydedici sadece burada gönderiliyor
  isleyici.okuVeIsle(dosyaInput.value, hataKaydedici);
});
Seviye 6

İleri Kavramlar: IoC/DI Konteynerleri Detaylı Konu Açıklamaları

Merkezi Yönetim: Manuelden Otomatiğe Geçiş

IoC/DI Konteynerleri, Bağımlılık Enjeksiyonu prensibini sadece bir kodlama stili olmaktan çıkarıp, tüm uygulamanın omurgasını yöneten merkezi bir yazılım bileşeni haline getirir.

Constructor veya Setter enjeksiyonu küçük ölçekte yeterli olsa da; yüzlerce modülün olduğu bir sistemde her şeyi manuel olarak birbirine bağlamak hem imkansız hem de hataya çok açıktır.

Bağımlılık Grafiği (Dependency Graph) Çözümleme

Konteynerlerin en sihirli görevi, karmaşık Bağımlılık Grafiğini analiz etmektir.

Bir A modülü B'ye, B modülü de C'ye ihtiyaç duyuyorsa; siz sadece A'yı istersiniz, Konteyner ise arka planda önce C'yi, sonra B'yi yaratır ve hiyerarşiyi bozmadan A'yı size hazır halde sunar.

Bootstrapping Otomasyonu: Uygulamanın ayağa kalkma ( bootstrapping ) sürecinde tüm bu "yaratma ve bağlama" işlemleri otomatikleşir.

Geliştirici, "Hangi nesne hangi sırayla yaratılmalı?" sorusuyla değil, sadece iş mantığıyla ilgilenir.

Yaşam Döngüsü ve Kaynak Yönetimi

IoC Konteynerleri sadece nesne yaratmaz, aynı zamanda bu nesnelerin Yaşam Döngüsü kurallarını da uygular.

Örneğin: Bir servisin her seferinde yeni mi yaratılacağı ( Transient ) yoksa tüm uygulama boyunca tek bir kopya mı kalacağı ( Singleton ) merkezi olarak belirlenir.

Sonuç: Geliştirici Verimliliği ve Temiz Mimari

Tüm bunların ışığında IoC/DI Konteynerleri; geliştiriciyi manuel nesne yönetim yükünden tamamen kurtarır.

Bu teknoloji, JavaScript ekosisteminde (özellikle InversifyJS, , NestJS gibi yapılarda) kurumsal seviyedeki uygulamaların Ölçeklenebilirlik ve Bakım Kolaylığı limitlerini belirleyen en kritik unsurdur.

IoC Konteyner Mimarisi Kontrol, Çözümleme ve Yaşam Döngüsü Yönetimi

Felsefi Temel: Kontrolün Gerçek Sahibi

IoC Konteyner, Kontrolün Tersine Çevrilmesi prensibini somut bir mühendislik aracına dönüştürür.

Geleneksel yapıda bir bileşen, bağımlılıklarını kendi "yaratma" gücüne sahipken; IoC modelinde bu güç elinden alınarak merkezi bir otoriteye devredilir, bileşen artık "yaratıcı" değil, sadece "talepkar" rolündedir.

İşleyiş Mekanizması: Üç Kritik Adım

Bir DI Konteyneri, arka planda son derece akıllı bir yazılım fabrikası gibi çalışır ve süreci şu üç temel adımda yönetir:

1. Kayıt (Registration): Geliştirici, konteynere hangi soyut ihtiyacın hangi somut gerçeklikle karşılanacağını söyler ve bu, sistemin

"kimlik rehberini" oluşturmaktır.

2. Çözümleme (Resolution): Siz bir ana servis istediğinizde, konteyner o servisin derinliklerine bakar ve gereken tüm alt bağımlılıkları tek tek tespit eder.

3. Otomatik Enjeksiyon: Konteyner, tespit ettiği tüm alt parçaları en doğru sırayla oluşturur ve ana servise enjekte ederek size tam teşekküllü bir obje teslim eder , buna Otomatik Bağımlılık Grafiği Çözümü denir.

Yaşam Döngüsü (Lifecycle) Stratejileri

Konteynerlerin en büyük gücü, bir objenin hafızada ne kadar süre kalacağını merkezi olarak belirlemesidir:

Singleton (Tekil): Uygulama ömrü boyunca sadece bir kez oluşturulur.

Herkes aynı örneği kullanır ( Veritabanı Bağlantısı gibi ).

Transient (Geçici): Her talepte sıfırdan yeni bir örnek yaratılır. Bağımsız işlem parçaları için idealdir.

Scoped (Kapsamlı): Sadece belirli bir sınırda ( Tek bir HTTP isteği süresince gibi ) tekil kalır, iş bitince yok edilir.

</>
Minyatür IoC Konteyner Örneği
Editörde Aç
<!DOCTYPE html>
<html lang="tr">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IoC Konteyner - Basit</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>

<body>
    <main class="card">
        <h2>📦 IoC Konteyner</h2>
        <p class="desc">Konteyner, bağımlılıkları otomatik çözer</p>

        <button id="calistirBtn">Servisi Çalıştır</button>
        <div id="output" class="output">---</div>
    </main>

    <script type="module" src="app.js?v=1.0.150"></script>
</body>

</html>
body {
    background: #0f172a;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    font-family: system-ui;
    margin: 0;
}

.card {
    background: #1e293b;
    padding: 2rem;
    border-radius: 16px;
    width: 400px;
    border-left: 4px solid #c084fc;
}

h2 {
    color: #f1f5f9;
    margin: 0 0 0.5rem 0;
}

.desc {
    color: #94a3b8;
    font-size: 0.9rem;
    margin-bottom: 2rem;
}

button {
    background: #c084fc;
    color: #020617;
    border: none;
    padding: 12px 24px;
    border-radius: 8px;
    font-weight: 600;
    cursor: pointer;
    width: 100%;
    margin-bottom: 1rem;
}

button:hover {
    background: #a855f7;
}

.output {
    background: #0f172a;
    padding: 1rem;
    border-radius: 8px;
    color: #e2e8f0;
    font-family: monospace;
    min-height: 60px;
}
// container.js - Sadece iki metod: kaydet ve çöz
export class Container {
    constructor() {
        this.kayitlar = new Map();
    }

    // Kayıt: Bu sınıf nasıl yaratılacak?
    kaydet(anahtar, yaratici) {
        this.kayitlar.set(anahtar, yaratici);
    }

    // Çözümle: Bana bunu ver, ihtiyaçlarını sen hallet
    coz(anahtar) {
        const yaratici = this.kayitlar.get(anahtar);
        if (!yaratici) throw new Error(`${anahtar} bulunamadı`);
        
        // Yaratici fonksiyonuna container'ı ver ki alt bağımlılıkları çözebilsin
        return yaratici(this);
    }
}
// 1. Basit bir Utils (loglama yapan)
export class Utils {
    log(mesaj) {
        return `📝 [LOG] ${mesaj}`;
    }
}

// 2. İş yapan ana servis (Utils'e bağımlı)
export class IsServisi {
    constructor(utils) {
        this.utils = utils;
    }

    isYap() {
        return this.utils.log("İşlem başarılı!");
    }
}
import { Container } from './container.js';
import { Utils, IsServisi } from './servisler.js';

// 1. Konteyner oluştur
const container = new Container();

// 2. Kayıtları yap (Konteyner'a sınıfları tanıt)
container.kaydet('utils', () => new Utils());

container.kaydet('isServisi', (c) => {
    // ✨ Sihir: Konteyner'dan utils'i İSTE!
    // Nasıl yaratıldığını bilmiyoruz, sadece istiyoruz.
    const utils = c.coz('utils');
    return new IsServisi(utils);
});

// 3. Kullan
const btn = document.getElementById('calistirBtn');
const output = document.getElementById('output');

btn.addEventListener('click', () => {
    // Sadece 'isServisi' istiyoruz, 
    // konteyner onun utils'e ihtiyacı olduğunu biliyor!
    const servis = container.coz('isServisi');
    
    const sonuc = servis.isYap();
    output.innerHTML = `✅ ${sonuc}`;
});

🧭 Opsiyonel Okuma Notu

Bilgilendirme: Bu bölüm, konuların arka planına ve düşünsel temellerine daha derin bir bakış sunmak amacıyla hazırlanmıştır.

  • Matematiksel, tarihsel ve felsefî içerikler isteğe bağlı olarak okunabilir.
  • Her bölümün içerik seviyesi ve yoğunluğu farklılık gösterebilir.
  • Temel düzey kullanıcılar için zorunlu değildir, ileri düzey okuma niteliğindedir.
JavaScript Modüler Programlama ve Kod Organizasyonu

Modüler Programlama ve Kod Organizasyonu ( Felsefi ve Tarihsel Açıklama )

JavaScript'in tek küresel kapsam kısıtlamasına karşı geliştirilen mimari mücadeleyi, Modül Desenleri, CommonJS ve AMD gibi tarihsel çözümlerin ardındaki felsefeyi ve büyük ölçekli uygulamaların neden zorunlu olarak modülerleştiğini derinlemesine inceleyin.

Ana Konu Felsefi ve Tarihsel Açıklama
Seviye 5

Modülerliğin Tarihi Kökleri ve Kapsam Yönetimi Detaylı Konu Açıklamaları

Felsefi İhtiyaç: Küresel Kapsamın Kaos Teorisi

Modern JavaScript bugün sahip olduğu ileri düzey modül sistemine bir gecede ulaşmadı.

JavaScript'in ilk yıllarında en büyük mimari engel, dilin tek bir küresel yürütme kapsamı üzerine inşa edilmiş olmasıydı.

Bu durum, herhangi bir betik dosyasında tanımlanan değişkenlerin kontrolsüzce ortak bir alana sızması anlamına geliyordu.

Matematiksel Zorluk: İsim Çakışması (Namespace Collision)

Küresel kapsamın en tehlikeli yan etkisi, İsim Çakışması sorunudur.

Büyük ölçekli bir uygulamada veya dış kütüphanelerin entegre edildiği projelerde, iki farklı kod parçasının aynı isimde bir değişken ( const data gibi ) tanımlaması kaçınılmazdır.

Bütünlük İhlali: Bir kodun diğerini sessizce ezmesi, uygulamanın davranışını öngörülemez hale getirir.

Bu durum, matematiksel olarak veri bütünlüğünün bozulmasıdır ve yazılımın Güvenilirlik AQC'sini tamamen ortadan kaldırır.

Kapsülleme Eksikliği ve Bilgi Gizleme

Nesne Yönelimli Programlamanın temel taşı olan Bilgi Gizleme, başlangıçta dilde mevcut değildi.

Bir objenin iç mantığını veya hassas verilerini "private" yaparak dış dünyadan saklamak imkansızdı.

Her şey küresel vitrinde açık ve müdahaleye hazırdı.

Yaratıcı Çözümler: Modülerliğin İlk Adımları

Bu kısıtlamalar, geliştiricileri dilin mevcut Fonksiyonel Kapsam özelliğini kullanarak mimari hileler geliştirmeye itti.

Bu dönemin en büyük felsefi başarısı olan IIFE ( Hemen Yürütülen Fonksiyon İfadeleri ), kodu kendi içine hapsederek küresel kapsamı koruma altına alan bir "yazılım kalkanı" görevi gördü.

Sonuç olarak Modülerliğin Tarihi Kökleri; dilin eksiklerini mimari birer sanat eserine dönüştüren geliştiricilerin, izolasyon ve düzen arayışının hikayesidir.

Bu dönemde atılan temeller, bugünün modern paketleyicilerinin ve modül sistemlerinin felsefi zeminini hazırlamıştır.

IIFE (Immediately Invoked Function Expression) Kapsamın Kalesi

Tarihsel Zorunluluk: Global Kaosa Karşı İzolasyon

IIFE, JavaScript'in erken dönemlerinde modern modül sistemlerinin yokluğunda geliştirilen en kritik mimari çözümdür.

var anahtar kelimesinin "blok kapsamı" desteğine sahip olmaması ve her değişkenin kontrolsüzce Global Kapsama sızması, büyük ölçekli projelerde yıkıcı isim çakışmalarına neden oluyordu.

İşlevsel Kalkan: IIFE'nin temel mekaniği, JavaScript'in Fonksiyonel Kapsam kuralını bir koruma kalkanı olarak kullanmaktır.

Tanımlandığı anda otomatik olarak yürütülen bu fonksiyonlar, içindeki tüm değişkenleri ve mantığı dış dünyadan tamamen izole eden

"tek kullanımlık bir kapsül" oluşturur.

Felsefi Sonuç: Bilgi Gizleme (Encapsulation)

Manuel Kapsülleme: IIFE, geliştiricinin dilin doğal bir özelliği olmayan Veri Gizleme prensibini manuel olarak uygulamasını sağlayan ilk yapısal araçtır.

Bu yapı sayesinde, bir kütüphane yazarı kendi iç değişkenlerini dışarıdaki kodların erişimine kapatabilir, sadece istenen bölümleri kontrollü bir şekilde dışarıya açabilirdi.

İsim Alanı Güvenliği: Bir IIFE içinde tanımlanan var x = 10; ifadesi, dışarıdaki başka bir var x ile asla çakışmaz.

Bu, yazılım mühendisliğinde "Güvenli İsim Alanı" oluşturmanın en ilkel ama en etkili yoluydu.

Modülerliğin İlk Adımı: İzolasyon İhtiyacı

Bugün kullandığımız karmaşık modül paketleyicilerin atası IIFE felsefesidir.

Modülerlik, sadece kodun parçalara ayrılması değil, bu parçaların birbirinin özel alanına müdahale etmemesi ihtiyacından doğmuştur.

Sonuç olarak IIFE; JavaScript'i bir "script dili" olmaktan çıkarıp, yönetilebilir ve izole bileşenler içeren profesyonel bir yazılım platformuna dönüştüren ilk felsefi sıçramadır.

Küresel kapsamın kirliliğine karşı çekilen bu kale duvarları, modern modüler programlamanın zeminini hazırlamıştır.

Modül Deseni (Module Pattern) ve Revealing Module Pattern Genel Bilgiler

Modül Deseni: İlk Gerçek Modülerlik Kalıbı

Modül Deseni, IIFE'nin sağladığı temel kapsam izolasyonunu bir üst seviyeye taşıyarak, JavaScript'te profesyonel bir Bilgi Gizleme mekanizması kurar.

Sadece değişkenleri dış dünyadan saklamakla kalmaz, aynı zamanda dışarıya hangi özelliklerin ve fonksiyonların sunulacağını belirleyen kontrollü bir Public APIoluşturur.

Kapanım (Closure) ve Veri Güvenliği

Sürekli Hafıza: Modül deseninin kalbinde JavaScript'in en güçlü özelliklerinden biri olan Closure yatar.

IIFE çalışmasını tamamlayıp yığın dışına çıksa bile, döndürülen nesne içindeki fonksiyonlar, IIFE içindeki "özel" değişkenlere erişmeye devam eder.

İç Durumun Korunması: Bu yapı, modülün iç verisinin dışarıdan doğrudan müdahale edilerek bozulmasını engeller.

Dış dünya sadece modülün "izin verdiği" kapılardan içeri girebilir; bu da yazılımın Veri Bütünlüğü AQC'sini sağlar.

Revealing Module Pattern: Okunabilirlik Devrimi

Açığa Çıkarma Modül Deseni, klasik desenin mantığını korurken kod organizasyonunu daha şık ve yönetilebilir bir hale getirir.

Klasik yapıda genel metotlar doğrudan return edilen nesnenin içinde tanımlanırken, bu desende tüm mantık önce IIFE içinde bir bütün olarak yazılır.

Geliştirici Ergonomisi: Modülün sonunda, sadece dışarıya açılmak istenen fonksiyonların ve değişkenlerin referansları bir nesne olarak döndürülür.

Bu sayede modülün "neyi dışarı açtığını" görmek için dosyanın en sonundaki kısa listeye bakmak yeterli olur; bu da Bakım Kolaylığı sağlar.

Sonuç olarak Modül Deseni ve onun türevleri; JavaScript'i karmaşık bir "script" yığını olmaktan çıkarıp, her parçası kendi sırlarını saklayan ve dış dünyayla resmi protokollerle haberleşen profesyonel bir sisteme dönüştürmüştür.

Bugün kullandığımız ES Modülleri, felsefi olarak bu desenlerin üzerine inşa edilmiştir.

Bilgilendirme

Örnek, Klasik Modül Deseni (Classic Module Pattern) mantığını göstermek amacıyla hazırlanmıştır.

_sayac ve _gizliID gibi özel alanlar closure ile korunur, dışarıdan erişilemez.

UI üzerinden yapılan işlemler ( Artır / Sıfırla ) yalnızca demo amaçlıdır ve modülün genel kullanım mantığını öğrenmek içindir.

Gerçek projelerde benzer mantık, güvenli veri kaynakları ve API’lerle birleştirilerek kullanılabilir.

Bu örnek, Açığa Çıkarma Modül Deseni’nin çalışma prensibini ve modüler kod organizasyonunu öğrenmeniz için hazırlanmıştır.

</>
Klasik Modül Deseni (Classic Module Pattern) - Özel Sayaç Örneği
Editörde Aç
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Klasik Modül Deseni</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
    <div class="kart">
        <h2>📦 Klasik Modül Deseni</h2>
        <p class="aciklama">Özel (private) sayaç, genel (public) metodlar</p>
        
        <div class="sayaç-kutu">
            <span id="sayaçDeger">0</span>
        </div>
        
        <div class="butonlar">
            <button id="artirBtn">➕ Artır</button>
            <button id="sifirlaBtn">🔄 Sıfırla</button>
        </div>
        
        <div class="konsol">
            <div class="konsol-baslik">📋 Konsol Çıktısı (F12)</div>
            <div id="logAlan">Butona tıklayın...</div>
        </div>
        
        <div class="bilgi">
            <small>✨ <code>_sayac</code> ve <code>_gizliID</code> dışarıdan erişilemez!</small>
        </div>
    </div>

    <script src="modul.js?v=1.0.150"></script>
</body>
</html>
body {
    font-family: 'Segoe UI', system-ui, sans-serif;
    background: #0f172a;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
    padding: 1rem;
}

.kart {
    background: #1e293b;
    border-radius: 24px;
    padding: 2rem;
    width: 400px;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
    border-left: 4px solid #f97316;
}

h2 {
    color: #f1f5f9;
    margin: 0 0 0.5rem 0;
    font-size: 1.5rem;
}

.aciklama {
    color: #94a3b8;
    font-size: 0.9rem;
    margin-bottom: 2rem;
    padding-bottom: 1rem;
    border-bottom: 1px dashed #334155;
}

.sayaç-kutu {
    background: #0f172a;
    border-radius: 16px;
    padding: 2rem;
    text-align: center;
    margin-bottom: 1.5rem;
}

#sayaçDeger {
    font-size: 4rem;
    font-weight: 700;
    color: #f97316;
    text-shadow: 0 0 20px rgba(249, 115, 22, 0.3);
}

.butonlar {
    display: flex;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

button {
    flex: 1;
    padding: 1rem;
    border: none;
    border-radius: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
}

#artirBtn {
    background: linear-gradient(135deg, #f97316, #fb923c);
    color: #0f172a;
}

#artirBtn:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 20px rgba(249, 115, 22, 0.3);
}

#sifirlaBtn {
    background: #334155;
    color: #f1f5f9;
}

#sifirlaBtn:hover {
    background: #475569;
}

.konsol {
    background: #0f172a;
    border-radius: 12px;
    padding: 1rem;
    margin-bottom: 1rem;
}

.konsol-baslik {
    color: #94a3b8;
    font-size: 0.8rem;
    margin-bottom: 0.5rem;
}

#logAlan {
    color: #4ade80;
    font-family: monospace;
    font-size: 0.9rem;
    min-height: 2rem;
}

.bilgi {
    background: #f97316;
    color: #0f172a;
    padding: 0.75rem;
    border-radius: 8px;
    font-size: 0.85rem;
    text-align: center;
}

.bilgi code {
    background: #0f172a;
    color: #f97316;
    padding: 0.2rem 0.4rem;
    border-radius: 4px;
}
// 📦 Klasik Modül Deseni (Classic Module Pattern)
var SayaçModul = (function () {
    // --- Özel (Private) alan: Dışarıdan kesinlikle erişilemez ---
    var _sayac = 0;          // Closure ile korunan özel değişken
    var _gizliID = "SAYAÇ_1"; // Modülün iç kimliği

    // Özel yardımcı fonksiyon
    function _logla(mesaj) {
        var logAlan = document.getElementById("logAlan");
        var yeniLog = `[${_gizliID}] ${mesaj} (değer: ${_sayac})`;
        
        if (logAlan) {
            logAlan.innerHTML = yeniLog;
        }
        console.log(yeniLog);
    }

    // --- Genel (Public) arayüz: Dışarıya açılan metodlar ---
    return {
        // Sayacı 1 artır
        artir: function () {
            _sayac++;
            _logla("➕ Artırıldı");
            return _sayac;
        },
        
        // Sayacı sıfırla
        sifirla: function () {
            _sayac = 0;
            _logla("🔄 Sıfırlandı");
            return _sayac;
        },
        
        // Güncel değeri göster
        degerAl: function () {
            return _sayac;
        }
    };
})();

// --- UI Bağlantıları ---
document.getElementById("artirBtn").addEventListener("click", function () {
    SayaçModul.artir();
    document.getElementById("sayaçDeger").textContent = SayaçModul.degerAl();
});

document.getElementById("sifirlaBtn").addEventListener("click", function () {
    SayaçModul.sifirla();
    document.getElementById("sayaçDeger").textContent = SayaçModul.degerAl();
});

// Başlangıç değerini göster
document.getElementById("sayaçDeger").textContent = SayaçModul.degerAl();

// 🧪 Test: Özel üyelere erişmeyi dene (hepsi undefined)
console.log("Dışarıdan _sayac:", SayaçModul._sayac);      // undefined
console.log("Dışarıdan _gizliID:", SayaçModul._gizliID);  // undefined
console.log("Dışarıdan _logla:", SayaçModul._logla);      // undefined

Bilgilendirme

Bu bir simülasyon örneğidir; canlı veri veya API çağrısı yoktur.

Rapor değerleri tamamen modül içindeki rastgele hesaplamalarla üretilir.

Yalnızca demo ve eğitim amaçlıdır.

Gerçek projelerde benzer mantık, güvenli veri kaynakları ve API’lerle birleştirilerek kullanılabilir.

Bu örnek, Açığa Çıkarma Modül Deseni’nin çalışma prensibini ve modüler kod organizasyonunu öğrenmeniz için hazırlanmıştır.

</>
Açığa Çıkarma Modül Deseni (Revealing Module Pattern) - Rapor Örneği
Editörde Aç
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Açığa Çıkarma Modül Deseni</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
    <div class="kart">
        <h2>📋 Açığa Çıkarma Modül Deseni</h2>
        <p class="aciklama">Tüm mantık içte, API sonradan açığa çıkarılır</p>
        
        <div class="bilgi-kutusu">
            <div class="bilgi-satiri">
                <span class="etiket">Rapor Tipi:</span>
                <span class="deger" id="raporTipi">Finansal</span>
            </div>
            <div class="bilgi-satiri">
                <span class="etiket">Hesaplanan:</span>
                <span class="deger" id="hesapDeger">---</span>
            </div>
        </div>
        
        <div class="format-butonlar">
            <button id="pdfBtn" class="format-btn" data-format="PDF">📄 PDF Rapor</button>
            <button id="excelBtn" class="format-btn" data-format="Excel">📊 Excel Rapor</button>
            <button id="htmlBtn" class="format-btn" data-format="HTML">🌐 HTML Rapor</button>
        </div>
        
        <div class="cikti-alani" id="ciktiAlan">
            Bir format seçin...
        </div>
        
        <div class="bilgi">
            <small>
                🔍 <strong>Okunabilirlik:</strong> 
                <code>return { exportEt: _disaAktar, tipi: _raporTipi }</code> 
                ile API hemen anlaşılır.
            </small>
        </div>
    </div>

    <script src="rapor-modul.js?v=1.0.150"></script>
</body>
</html>
body {
    font-family: 'Segoe UI', system-ui, sans-serif;
    background: #0f172a;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
    padding: 1rem;
}

.kart {
    background: #1e293b;
    border-radius: 24px;
    padding: 2rem;
    width: 480px;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
    border-left: 4px solid #10b981;
}

h2 {
    color: #f1f5f9;
    margin: 0 0 0.5rem 0;
    font-size: 1.5rem;
}

.aciklama {
    color: #94a3b8;
    font-size: 0.9rem;
    margin-bottom: 2rem;
    padding-bottom: 1rem;
    border-bottom: 1px dashed #334155;
}

.bilgi-kutusu {
    background: #0f172a;
    border-radius: 12px;
    padding: 1.25rem;
    margin-bottom: 1.5rem;
}

.bilgi-satiri {
    display: flex;
    justify-content: space-between;
    margin-bottom: 0.75rem;
}

.bilgi-satiri:last-child {
    margin-bottom: 0;
}

.etiket {
    color: #94a3b8;
    font-size: 0.9rem;
}

.deger {
    color: #10b981;
    font-weight: 600;
    font-size: 1.1rem;
}

.format-butonlar {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}

.format-btn {
    padding: 0.75rem;
    border: none;
    border-radius: 8px;
    background: #334155;
    color: #f1f5f9;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    font-size: 0.85rem;
}

.format-btn:hover {
    background: #10b981;
    color: #0f172a;
    transform: translateY(-2px);
}

.cikti-alani {
    background: #0f172a;
    border-radius: 12px;
    padding: 1.25rem;
    margin-bottom: 1.5rem;
    font-family: monospace;
    color: #f1f5f9;
    min-height: 80px;
    border: 1px solid #334155;
}

.bilgi {
    background: #10b981;
    color: #0f172a;
    padding: 1rem;
    border-radius: 8px;
    font-size: 0.85rem;
}

.bilgi code {
    background: #0f172a;
    color: #10b981;
    padding: 0.2rem 0.4rem;
    border-radius: 4px;
    font-size: 0.8rem;
}

@media (max-width: 500px) {
    .kart {
        width: 100%;
        padding: 1.5rem;
    }
    
    .format-butonlar {
        grid-template-columns: 1fr;
    }
}
// 📋 Açığa Çıkarma Modül Deseni (Revealing Module Pattern)
var RaporModulu = (function () {
    // --- Tüm üyeler önce burada tanımlanır (Okunabilirlik artışı!) ---
    
    // Özel değişkenler
    var _raporTipi = "Finansal";
    var _versiyon = "2.1.0";
    var _olusturmaSayisi = 0;

    // Özel yardımcı fonksiyon (dışarı açılmayacak)
    function _rastgeleDegerHesapla() {
        return (Math.random() * 1000).toFixed(2);
    }

    // Özel log fonksiyonu
    function _logla(islem) {
        _olusturmaSayisi++;
        console.log(`[${_raporTipi}] ${islem} (${_olusturmaSayisi}. rapor)`);
    }

    // Dışarı açılacak fonksiyon - Rapor oluştur
    function _disaAktar(format) {
        _logla(`Rapor oluşturuluyor: ${format}`);
        var hesaplanan = _rastgeleDegerHesapla();
        
        // UI'ı güncelle
        document.getElementById("hesapDeger").textContent = hesaplanan;
        
        return `📋 ${_raporTipi} Rapor (${format} formatı)
────────────────
Tutar: ${hesaplanan} ₺
Versiyon: ${_versiyon}
Oluşturma: #${_olusturmaSayisi}`;
    }

    // Dışarı açılacak - Rapor tipini değiştir
    function _tipDegistir(yeniTip) {
        _raporTipi = yeniTip;
        document.getElementById("raporTipi").textContent = yeniTip;
        _logla(`Tip değiştirildi: ${yeniTip}`);
        return `Rapor tipi "${yeniTip}" olarak güncellendi`;
    }

    // --- Açığa Çıkarma (Revealing) Kısmı ---
    // Burada hangi iç fonksiyonların dışarı açılacağı net olarak görülür!
    return {
        // İç fonksiyon, dışarıda "exportEt" adıyla görünecek
        exportEt: _disaAktar,
        
        // İç fonksiyon, dışarıda "tipGuncelle" adıyla görünecek
        tipGuncelle: _tipDegistir,
        
        // Değişkeni de açığa çıkarabiliriz (salt-okunur gibi)
        mevcutTip: _raporTipi,
        
        // Versiyon bilgisi
        versiyon: _versiyon
    };
})();

// --- UI Bağlantıları ---
var ciktiAlan = document.getElementById("ciktiAlan");
var raporTipiEl = document.getElementById("raporTipi");

// Format butonlarına tıklama
document.querySelectorAll(".format-btn").forEach(function(btn) {
    btn.addEventListener("click", function() {
        var format = this.getAttribute("data-format");
        var sonuc = RaporModulu.exportEt(format);
        ciktiAlan.innerHTML = sonuc.replace(/\n/g, '<br>');
    });
});

// Başlangıç değerlerini ayarla
raporTipiEl.textContent = RaporModulu.mevcutTip;

// 🧪 Test: Özel üyelere erişim yok!
console.log("Dışarıdan _versiyon:", RaporModulu._versiyon); // undefined
console.log("Dışarıdan _olusturmaSayisi:", RaporModulu._olusturmaSayisi); // undefined
console.log("Dışarıdan _logla:", RaporModulu._logla); // undefined

// ✅ Açığa çıkarılanlar:
console.log("Modül API'si:", Object.keys(RaporModulu)); 
// ["exportEt", "tipGuncelle", "mevcutTip", "versiyon"]
Seviye 6

Bağımlılık Yönetiminin Evrimi (ES6 Öncesi) Detaylı Konu Açıklamaları

Yerel Başarıdan Mimari Zorluğa

Modül Deseni (IIFE), kodun kendi içine hapsedilmesini sağlayarak küresel kapsam kirliliğini engellemiş ve bireysel modül bazında büyük bir başarı yakalamıştı.

Ancak bu başarı, projenin ölçeği büyüdükçe yerini yeni bir krize bıraktı bu kriz ise Bağımlılık Kaosu olarak adlandırılır.

Bir modülün izole kalması yeterli değildi; o modülün başka bir modüldeki fonksiyona veya veriye güvenli bir şekilde erişmesi gerekiyordu.

Yükleme Sırası ve "Spaghetti" Bağımlılıklar

ES6 öncesinde, hangi dosyanın hangi dosyadan önce yükleneceğini belirlemek tamamen geliştiricinin manuel çabasına dayanıyordu.

Yanlış bir <script> sırası, bağımlılığın henüz yüklenmemiş olması nedeniyle tüm uygulamanın çökmesine yol açabiliyordu.

Bu durum, yüzlerce dosyanın olduğu projelerde yönetilmesi imkansız bir "bağımlılık labirenti" yaratıyordu.

Çözüm Arayışı: Ortam Bazlı Standartlar

Bu mimari tıkanıklığı aşmak için JavaScript ekosistemi, çalışılan ortama göre iki devrimsel standart geliştirdi:

CommonJS (CJS): Sunucu tarafında ( Node.js ) doğdu.

Dosya sistemine doğrudan erişim olduğu için modülleri senkron olarak yükleme felsefesini benimsedi. require() ve module.exports ifadeleriyle bağımlılık yönetimini bir standarda bağladı.

AMD (Asynchronous Module Definition): Tarayıcı ortamının kısıtlamaları ( dosyaların internet üzerinden inmesi ) nedeniyle doğdu.

Modülleri ağ üzerinden asenkron olarak çekip, bağımlılıklar tamamlandığında çalıştıran bir yapı sundu.

Mühendislik Köprüsü: Modern Standartlara Geçiş

Bu tarihsel çözümler, JavaScript'in sadece küçük birer "script" parçası değil, büyük ölçekli kurumsal mühendislik projeleri inşa edilebilecek kadar olgun bir dil olduğunu kanıtlayan hayati köprülerdi.

Bugün kullandığımız "tek yönlü veri akışı" ve "modüler kompozisyon" gibi kavramların felsefi temelleri bu dönemde atılmıştır.

Özet olarak Bağımlılık Yönetiminin Evrimi; manuel yükleme listelerinden kurtulup, sistemin parçalarını otomatik ve güvenilir bir ağ içinde birbirine bağlama serüvenidir.

Sunucu Tarafının Güçlü ve Senkron Çözümü CommonJS

Felsefi Temel: Senkron Yükleme ve Bağımlılık Garantisi

CommonJS, özellikle Node.js gibi sunucu tarafı JavaScript ortamları için geliştirilmiş bir modülleme standardıdır.

Temel felsefesi, modüllerin yerel dosya sisteminden senkron olarak yüklenmesidir.

Sunucu ortamında diske erişim hızı milisaniyeler mertebesinde olduğu için, programın bir modül yüklenene kadar beklemesi ( bloklanması ) kabul edilebilir bir maliyettir.

Teknik İşleyiş: require() fonksiyonu çağrıldığında, JavaScript motoru hedef dosyanın kodunu okuyup yürütmeyi bitirene kadar yürütmeyi durdurur.

Bu yapı, bağımlılıkların her zaman kesin ve garantili bir sırayla yüklenmesini sağlayarak Tahmin Edilebilirlik AQC niteliğini korur.

Modül Kapsüllemesi: require() ve module.exports

CommonJS'in kalbinde, her dosyanın kendi özel kapsamında çalışması yatar.

Dış dünyaya açılacak üyeler module.exports veya exports nesneleri aracılığıyla tanımlanır.

Değerin Kopyalanması (Copy by Value): ESM'nin aksine CommonJS, dışa aktarılan değerleri bir nevi "kopyalayarak" verir.

Bir modülün module.exports nesnesine yapılan atamalar, onu içe aktaran üst modülleri anında etkilemez.

Bu izolasyon, beklenmedik yan etkileri sınırlayarak modüllerin bağımsızlığını artırır.

Statik Analiz Zorluğu ve Optimizasyon Darboğazı

CommonJS'in en büyük kısıtlaması, modern optimizasyon tekniklerine kapalı olmasıdır.

require çağrıları çalışma anında gerçekleştiği için, modül yolları değişkenler aracılığıyla dinamik olarak belirlenebilir

( require('./' + language +'.js') gibi ).

Tree Shaking Engeli: Paketleyici araçlar ( Webpack, Rollup ), kodun hangi parçalarının gerçekten kullanılacağını statik olarak analiz edemez.

Bu durum, kullanılmayan kodların silinmesi işlemini imkansız kılar veya etkisizleştirir.

Bu nedenle CommonJS, web tarayıcıları gibi dosya boyutunun kritik olduğu ortamlar için ideal değildir.

Özet ile CommonJS; basitliği, senkron güvenilirliği ve dosya tabanlı kapsüllemesiyle Node.js ekosisteminin devasa büyümesine zemin hazırlamıştır.

Modern ES Modülleri ile bayrağı devretse de, mevcut milyonlarca kütüphane ve sunucu tarafı mimarisi için hala hayat verici bir standart olmaya devam etmektedir.

Bilgilendirme

Bu bir simülasyon ve eğitim amaçlı Node.js modül örneğidir.

Fonksiyonlar (topla, cikar, carp) ve sabitler (PI, versiyon) dışa aktarılır ve başka dosyalarda import edilebilir.

Canlı veri veya kullanıcı girişine bağlı bir işlem yoktur. Modül, CommonJS dışa aktarma mantığını anlamak için hazırlanmıştır.

nizasyonunu öğrenmeniz için hazırlanmıştır.

</>
CommonJS Matematik Modülü - math.js Örneği
Editörde Aç
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CommonJS - Dışa Aktarma</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
    <div class="kart">
        <h2>
            📦 CommonJS Modül Sistemi
            <span class="node-badge">Node.js</span>
        </h2>
        <p class="aciklama">Dışa Aktarma (Export) - math.js</p>
        
        <div class="dosya-yapisi">
            <span>📁 proje/</span>
            │── 📄 math.js  <span style="color:#eab308"><-- Bu dosya</span><br>
            └── 📄 app.js
        </div>
        
        <div class="kod-kutusu">
            <div class="kod-baslik">
                <i>📄</i> math.js - Modül Dışa Aktarma
            </div>
            <pre class="kod-icerik"><code><span class="yorum">// 📐 Matematik fonksiyonları</span>
<span class="anahtar">function</span> <span class="fonksiyon">topla</span>(a, b) {
    <span class="anahtar">return</span> a + b;
}

<span class="anahtar">function</span> <span class="fonksiyon">cikar</span>(a, b) {
    <span class="anahtar">return</span> a - b;
}

<span class="yorum">// Sabit değerler</span>
<span class="anahtar">const</span> PI = 3.14159;
<span class="anahtar">const</span> VERSIYON = <span style="color:#a78bfa">"1.0.0"</span>;

<span class="yorum">// 🚀 Dışa aktarma (module.exports)</span>
<span class="anahtar">module.exports</span> = {
    topla: topla,
    cikar: cikar,
    PI: PI,
    versiyon: VERSIYON
};</code></pre>
        </div>
        
        <div class="bilgi-notu">
            <strong>📌 module.exports Nedir?</strong>
            <p style="margin: 0.5rem 0 0 0; font-size: 0.9rem;">
                CommonJS'te her dosya kendi <code>module</code> nesnesine sahiptir. 
                <code>module.exports</code>'e atanan her şey dışarıya açılır. 
                Burada 2 fonksiyon ve 2 sabit dışa aktarılıyor.
            </p>
        </div>
        
        <div class="footer">
            ⚡ Bu kod Node.js ortamında çalışır, tarayıcıda değil.
        </div>
    </div>
</body>
</html>
body {
    font-family: 'Segoe UI', system-ui, sans-serif;
    background: #0f172a;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
    padding: 1rem;
}

.kart {
    background: #1e293b;
    border-radius: 24px;
    padding: 2rem;
    width: 500px;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
    border-left: 4px solid #eab308;
}

h2 {
    color: #f1f5f9;
    margin: 0 0 0.5rem 0;
    font-size: 1.5rem;
    display: flex;
    align-items: center;
    gap: 8px;
}

.node-badge {
    background: #339933;
    color: white;
    font-size: 0.7rem;
    padding: 0.25rem 0.75rem;
    border-radius: 20px;
    font-weight: 400;
}

.aciklama {
    color: #94a3b8;
    font-size: 0.9rem;
    margin-bottom: 1.5rem;
    padding-bottom: 1rem;
    border-bottom: 1px dashed #334155;
}

.dosya-yapisi {
    background: #0f172a;
    border-radius: 12px;
    padding: 1rem;
    margin-bottom: 1.5rem;
    font-family: monospace;
    color: #eab308;
    border: 1px solid #334155;
}

.dosya-yapisi span {
    color: #94a3b8;
    margin-right: 1rem;
}

.kod-kutusu {
    background: #0f172a;
    border-radius: 12px;
    overflow: hidden;
    margin-bottom: 1.5rem;
}

.kod-baslik {
    background: #334155;
    padding: 0.75rem 1rem;
    color: #f1f5f9;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 8px;
}

.kod-baslik i {
    color: #eab308;
}

.kod-icerik {
    padding: 1.5rem;
    margin: 0;
    color: #f1f5f9;
    font-family: monospace;
    line-height: 1.6;
    border: 1px solid #334155;
    border-top: none;
    border-radius: 0 0 12px 12px;
}

.kod-icerik .yorum {
    color: #6b7280;
}

.kod-icerik .anahtar {
    color: #eab308;
}

.kod-icerik .fonksiyon {
    color: #60a5fa;
}

.bilgi-notu {
    background: #eab308;
    color: #0f172a;
    padding: 1rem;
    border-radius: 8px;
    font-size: 0.85rem;
}

.bilgi-notu code {
    background: #0f172a;
    color: #eab308;
    padding: 0.2rem 0.4rem;
    border-radius: 4px;
}

.footer {
    margin-top: 1.5rem;
    color: #94a3b8;
    font-size: 0.8rem;
    text-align: center;
}
// math.js - CommonJS Modülü
// Bu dosya Node.js ortamında çalışır

// Matematik fonksiyonları
function topla(a, b) {
  return a + b;
}

function cikar(a, b) {
  return a - b;
}

function carp(a, b) {
  return a * b;
}

// Sabit değerler
const PI = 3.14159;
const VERSIYON = "1.0.0";

// Tümünü tek bir nesne olarak dışa aktar
module.exports = {
  topla: topla,
  cikar: cikar,
  carp: carp,
  PI: PI,
  versiyon: VERSIYON,
};

// Alternatif: Tek tek dışa aktarma
// exports.topla = topla;
// exports.PI = PI;

Tarayıcılar İçin Asenkron Çözüm AMD (Asynchronous Module Definition)

Felsefi Temel: Bloke Etmeyen (Non-Blocking) Yükleme

AMD, adından da anlaşılacağı üzere modül yükleme sürecini asenkron olarak yönetmek için tasarlanmıştır.

Bu yaklaşım, modüllerin yerel diskten değil, ağ üzerinden indirildiği tarayıcı ortamları için bir zorunluluktur.

CommonJS'in senkron yapısı tarayıcıda sayfanın donmasına neden olurken, AMD bu sorunu ana iş parçacığını asla bloke etmeyerek çözer.

Kullanıcı Deneyimi Odaklılık: AMD'nin ana hedefi, bağımlılıklar indirilirken kullanıcı arayüzünün (UI) tepkisel kalmasını sağlamaktır.

Dosyalar arka planda paralel olarak inerken, tarayıcı diğer işlemleri yürütmeye devam edebilir; bu da modern web performansının temel taşlarından biridir.

Mekanizma: define() ve Callback Yapısı

AMD mimarisi, modülün ihtiyaç duyduğu her şeyi en başta açıkça ilan etmesine dayanır.

Bu süreç genellikle RequireJS gibi kütüphaneler aracılığıyla yönetilir ve define() fonksiyonu üzerinden yürütülür.

Çalışma Mantığı: Modül tanımlanırken bir "Bağımlılık Dizisi" belirtilir.

Tarayıcı bu listedeki tüm dosyaları indirip hazır hale getirdiğinde, modülün asıl kodunu barındıran "Callback Fonksiyonu" tetiklenir ve böylece kod, ancak tüm araçları elindeyken çalışmaya başlar.

Dinamik Yükleme (Lazy Loading) Avantajı

AMD'nin sunduğu en stratejik avantajlardan biri Dinamik Yükleme yeteneğidir.

Tüm uygulama kodunu tek seferde yüklemek yerine, sadece o anki ihtiyaca göre ( Kullanıcı bir butona tıkladığında veya admin paneline girdiğinde gibi senaryolarda örnekler verilebilir ) ilgili modüllerin indirilmesini tetikleyebilirsiniz.

Bu, başlangıç yükleme sürelerini radikal şekilde kısaltan bir performans optimizasyonudur.

Eleştiri: Callback Karmaşası

AMD'nin en büyük zayıflığı, bağımlılık sayısı arttıkça callback fonksiyonunun argüman listesinin yönetilemez hale gelmesidir.

Onlarca bağımlılığın sırasını ve isimlerini eşleştirmek geliştirici için zahmetli bir hal alabilir.

Ancak bu yapı, ES Modülleri gelene kadar tarayıcı tarafındaki en disiplinli ve performanslı standart olarak kalmıştır.

Sonuç olarak AMD; web uygulamalarını hantal ve bloklanan yapılardan kurtarıp, asenkron, dinamik ve kullanıcı dostu modüler sistemlere dönüştüren vizyoner bir standarttır.

Bilgilendirme

Bu bir simülasyon örneğidir; canlı veri veya gerçek API çağrısı yoktur.

AMD mantığını göstermek için bağımlılık çözümlemesi ve asenkron yükleme simüle edilmiştir.

math.js modülü bağımsızdır, app.js modülü math.js’e bağlıdır. UI’daki konsol çıktıları ve hesaplamalar tamamen demo amaçlıdır.

</>
AMD (Asynchronous Module Definition) - Tarayıcı İçin Asenkron Modül Sistemi
Editörde Aç
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AMD Basit Örnek</title>
    <link rel="stylesheet" href="style.css?v=1.0.150">
</head>
<body>
    <div class="kart">
        <h2>📦 AMD Basit Örnek</h2>
        <div class="alt-baslik">define() ile asenkron modül yönetimi</div>
        
        <!-- Modül Tanımları -->
        <div class="modul-gosterim">
            <div class="modul-satir">
                <span class="modul-isim">math.js</span>
                <span class="modul-kod">define([], function() { return { topla, carp, bol }; })</span>
            </div>
            <div class="modul-satir">
                <span class="modul-isim">app.js</span>
                <span class="modul-kod">define(['math'], function(math) { math.topla(5,3); })</span>
            </div>
        </div>
        
        <!-- Kontrol Butonları -->
        <div class="kontrol">
            <button id="yukleBtn">📥 Modülleri Yükle</button>
            <button id="tekrarBtn">🔄 Tekrar Dene</button>
        </div>
        
        <!-- Konsol Çıktısı -->
        <div class="konsol">
            <div class="konsol-baslik">📋 AMD Yükleme Süreci</div>
            <div id="konsolCikti">
                <div class="konsol-satir">⚪ Butona tıklayın...</div>
            </div>
        </div>
        
        <div class="info">
            ⚡ math.js yüklenirken app.js bekler, sonra callback çalışır
        </div>
    </div>

    <script src="amd-basit.js?v=1.0.150"></script>
</body>
</html>
body {
    font-family: system-ui, -apple-system, sans-serif;
    background: #0f172a;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    margin: 0;
    padding: 1rem;
}
.kart {
    background: #1e293b;
    border-radius: 20px;
    padding: 2rem;
    width: 500px;
    box-shadow: 0 20px 30px -10px rgba(0,0,0,0.5);
    border-left: 4px solid #f97316;
}
h2 {
    color: #f1f5f9;
    margin: 0 0 0.25rem 0;
    font-size: 1.5rem;
}
.alt-baslik {
    color: #94a3b8;
    font-size: 0.9rem;
    margin-bottom: 1.5rem;
    padding-bottom: 1rem;
    border-bottom: 1px dashed #334155;
}
.modul-gosterim {
    background: #0f172a;
    border-radius: 10px;
    padding: 1rem;
    margin-bottom: 1.5rem;
    border: 1px solid #334155;
}
.modul-satir {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    border-bottom: 1px dashed #334155;
}
.modul-satir:last-child {
    border-bottom: none;
}
.modul-isim {
    background: #f97316;
    color: #0f172a;
    padding: 0.25rem 0.75rem;
    border-radius: 20px;
    font-size: 0.8rem;
    font-weight: 600;
    min-width: 80px;
    text-align: center;
}
.modul-kod {
    color: #94a3b8;
    font-family: monospace;
    font-size: 0.85rem;
}
.kontrol {
    display: flex;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}
button {
    background: #334155;
    color: #f1f5f9;
    border: none;
    padding: 0.75rem 1rem;
    border-radius: 8px;
    font-weight: 600;
    cursor: pointer;
    flex: 1;
    transition: all 0.2s;
}
button:hover {
    background: #f97316;
    color: #0f172a;
}
.konsol {
    background: #0f172a;
    border-radius: 10px;
    padding: 1rem;
    border: 1px solid #f97316;
    min-height: 120px;
    font-family: monospace;
    font-size: 0.9rem;
}
.konsol-baslik {
    color: #f97316;
    font-weight: 600;
    margin-bottom: 0.75rem;
}
.konsol-satir {
    color: #e2e8f0;
    padding: 0.25rem 0;
    border-bottom: 1px dashed #334155;
}
.konsol-satir.yukleniyor {
    color: #f97316;
}
.konsol-satir.hazir {
    color: #4ade80;
}
.info {
    margin-top: 1rem;
    background: #f97316;
    color: #0f172a;
    padding: 0.75rem;
    border-radius: 6px;
    font-size: 0.8rem;
    text-align: center;
}
// amd-basit.js - AMD Basit Simülasyon

// Basit AMD Simülatörü
const AMD = {
    moduller: {},
    
    // define() fonksiyonu
    define: function(bagimliliklar, callback) {
        const modulAdi = this.getModulAdi();
        this.moduller[modulAdi] = {
            bagimliliklar: bagimliliklar,
            callback: callback,
            instance: null
        };
        console.log(`[AMD] ${modulAdi} tanımlandı`);
        return this;
    },
    
    // require() fonksiyonu
    require: function(modulAdi, callback) {
        konsolaEkle(`📥 require('${modulAdi}') çağrıldı`, '#f97316');
        
        const modul = this.moduller[modulAdi];
        if (!modul) {
            konsolaEkle(`❌ Hata: ${modulAdi} bulunamadı!`, '#ef4444');
            return;
        }
        
        // Bağımlılıkları yükle
        this.modulYukle(modulAdi, function(instance) {
            konsolaEkle(`✅ callback çalışıyor...`, '#4ade80');
            callback(instance);
        });
    },
    
    // Modül ve bağımlılıklarını yükle
    modulYukle: function(modulAdi, callback) {
        const modul = this.moduller[modulAdi];
        
        // Daha önce yüklendiyse direkt döndür
        if (modul.instance) {
            callback(modul.instance);
            return;
        }
        
        // Bağımlılık yoksa direkt çalıştır
        if (modul.bagimliliklar.length === 0) {
            konsolaEkle(`   ⚡ ${modulAdi} bağımlılıksız, hemen çalışıyor...`, '#94a3b8');
            modul.instance = modul.callback();
            callback(modul.instance);
            return;
        }
        
        // Bağımlılıkları yükle
        konsolaEkle(`   ⏳ ${modulAdi} bağımlılıkları yükleniyor: ${modul.bagimliliklar.join(', ')}`, '#94a3b8');
        
        const yuklenecekler = modul.bagimliliklar.length;
        let yuklenenler = 0;
        const bagimlilikInstance = {};
        
        modul.bagimliliklar.forEach(function(bagimlilik) {
            // Asenkron yüklemeyi simüle et (setTimeout)
            setTimeout(function() {
                const bagModul = AMD.moduller[bagimlilik];
                if (bagModul) {
                    if (!bagModul.instance) {
                        bagModul.instance = bagModul.callback();
                    }
                    bagimlilikInstance[bagimlilik] = bagModul.instance;
                    yuklenenler++;
                    
                    konsolaEkle(`   ✅ ${bagimlilik} yüklendi`, '#4ade80');
                    
                    if (yuklenenler === yuklenecekler) {
                        konsolaEkle(`   🎯 Tüm bağımlılıklar hazır, ${modulAdi} çalışıyor...`, '#8b5cf6');
                        modul.instance = modul.callback(bagimlilikInstance);
                        callback(modul.instance);
                    }
                }
            }, 800); // 800ms gecikme (ağ gecikmesi simülasyonu)
        });
    },
    
    // Hangi modülün çağrıldığını bul (basit)
    getModulAdi: function() {
        const stack = new Error().stack;
        if (stack.includes('math')) return 'math';
        return 'app';
    }
};

// Konsol çıktısı fonksiyonu
function konsolaEkle(mesaj, renk = '#e2e8f0') {
    const konsol = document.getElementById('konsolCikti');
    if (konsol) {
        konsol.innerHTML += `<div class="konsol-satir" style="color: ${renk}">${mesaj}</div>`;
        konsol.scrollTop = konsol.scrollHeight;
    }
}

// Modülleri tanımla (define)

// 1. math.js modülü - Hiç bağımlılığı yok
AMD.define([], function() {
    console.log('math.js modülü çalıştı');
    return {
        topla: function(a, b) {
            return a + b;
        },
        carp: function(a, b) {
            return a * b;
        },
        bol: function(a, b) {
            return b !== 0 ? a / b : 'bölen 0 olamaz';
        },
        bilgi: 'Matematik modülü v1.0'
    };
});

// 2. app.js modülü - math.js'e bağımlı
AMD.define(['math'], function(math) {
    console.log('app.js modülü çalıştı, math hazır');
    return {
        hesapla: function(x, y) {
            const toplam = math.topla(x, y);
            const carpim = math.carp(x, y);
            return {
                toplam: toplam,
                carpim: carpim,
                mesaj: `${x} + ${y} = ${toplam}, ${x} × ${y} = ${carpim}`
            };
        }
    };
});

// UI Olayları
document.getElementById('yukleBtn').addEventListener('click', function() {
    // Konsolu temizle
    document.getElementById('konsolCikti').innerHTML = '';
    
    // app.js modülünü yükle
    AMD.require('app', function(app) {
        const sonuc = app.hesapla(6, 3);
        
        konsolaEkle('────────────────', '#334155');
        konsolaEkle(`📊 ${sonuc.mesaj}`, '#8b5cf6');
        konsolaEkle(`   Toplam: ${sonuc.toplam}`, '#94a3b8');
        konsolaEkle(`   Çarpım: ${sonuc.carpim}`, '#94a3b8');
    });
});

document.getElementById('tekrarBtn').addEventListener('click', function() {
    // Instance'ları sıfırla (yeniden yükleme simülasyonu)
    AMD.moduller.math.instance = null;
    AMD.moduller.app.instance = null;
    
    document.getElementById('konsolCikti').innerHTML = '';
    konsolaEkle('🔄 Yeniden başlatıldı', '#f97316');
});

İçerik Tamamlandı

Bu konunun temel içeriği burada sona eriyor

Tebrikler! 🎉

Bu konuyu başarıyla tamamladınız! Sabırla ve azimle öğrendiğiniz her şey, programlama yolculuğunuzda önemli bir adımdır. Öğrendiklerinizi pekiştirmek için kod örneklerini tekrar gözden geçirebilir ve kendi projelerinizde uygulayabilirsiniz.

Sonraki Adımlar: Bu sayfadaki içeriği tamamladıktan sonra, öğrendiklerinizi pekiştirmek ve ilerlemek için aşağıdaki kaynaklardan yararlanabilirsiniz:

  • Kod İstatistikleri: Bu sayfadaki tüm kod örneklerinin seviye dağılımını görüntüleyerek, hangi zorluk seviyelerinde ne kadar pratik yaptığınızı görebilirsiniz.
  • Öğrenme Yolu: JavaScript öğrenme yolculuğunuzdaki ilerlemenizi takip edebilir ve sonraki konuları planlayabilirsiniz.
  • Referanslar: Bu konuyla ilgili detaylı dokümantasyon ve kaynakları inceleyerek bilginizi derinleştirebilirsiniz.

Öğrenme İpuçları

  • Kod örneklerini kopyalayıp kendi editörünüzde deneyin
  • Her örneği çalıştırın ve sonucu gözlemleyin
  • Örnekleri değiştirip kendi versiyonlarınızı oluşturun
  • Öğrendiklerinizi not alın ve tekrar edin
  • Pratik yapmak için kendi mini projelerinizi oluşturun

Sonraki Konu

Öğrenme yolculuğunuzda bir sonraki adımınızı keşfedin ve öğrenmeye devam edin!

Sonraki Konuya Git

Kod Örnekleri İstatistikleri

Bu sayfadaki tüm kod örneklerinin seviye dağılımı

0 Toplam Örnek Bu kısımda sayfa içerisinde ki zorluk derecesine bakılmaksızın toplam örnek sayısını verir
0 HTML Örnekleri Bu sayfada ki her bir örnek içerisinde ki html bölümlerinin sayısını verir
0 CSS Örnekleri Bu sayfada ki her bir örnek içerisinde ki css bölümlerinin sayısını verir
0 JavaScript Örnekleri Bu sayfada ki her bir örnek içerisinde ki js bölümlerinin sayısını verir

HTML Seviye Dağılımı

Başlangıç 0
0%
Temel HTML yapıları ve basit etiketler
Orta 0
0%
Semantik HTML ve form yapıları
İleri 0
0%
Kompleks yapılar ve HTML5 API'leri
Uzman 0
0%
Gelişmiş teknikler ve optimizasyon

CSS Seviye Dağılımı

Başlangıç 0
0%
Temel CSS özellikleri ve seçiciler
Orta 0
0%
Flexbox, Grid ve animasyonlar
İleri 0
0%
Gelişmiş teknikler ve preprocessors
Uzman 0
0%
Kompleks layout'lar ve optimizasyon

JavaScript Seviye Dağılımı

Başlangıç 0
0%
Temel JavaScript ve DOM manipülasyonu
Orta 0
0%
ES6+ özellikleri ve async programlama
İleri 0
0%
Gelişmiş patterns ve framework'ler
Uzman 0
0%
Performans optimizasyonu ve mimari

Kod Dosyaları

Bu sayfadaki tüm kod dosyalarını dil ve seviyeye göre filtreleyin

Modülerlik ve Kod Organizasyonu Syntax Referansı Tüm modül ve bağımlılık yönetimi syntax'larını tek yerde görüntüle
ES Modülleri (ESM - ECMAScript Modules)
Named Export
export const PI = 3.14; export function topla(a, b) { return a + b; } Birden fazla üye dışa aktarılır. Her üye kendi adıyla import edilebilir
Default Export
const DB_BAGLANTISI = { url: 'local' }; export default DB_BAGLANTISI; Modül başına sadece bir tane. İçe aktarılırken herhangi bir isimle alınabilir
Named Import
import { topla, PI } from './math.js'; Belirli üyeleri içe aktarır. Süslü parantez içinde isimleri belirtilir
Default Import
import baglanti from './modül.js'; Varsayılan üyeyi içe aktarır. Süslü parantez kullanılmaz, isim serbesttir
Namespace Import
import * as Matematik from './math.js'; Tüm üyeleri bir nesne altında toplar. Nokta notasyonu ile erişilir
Live Bindings
export let sayac = 0; export function artir() { sayac++; } Canlı bağlayıcılar, değer güncellenir. Tüm import eden modüller anında görür
Bağımlılık Enjeksiyonu (DI)
Constructor Injection
class RaporServisi { constructor(logger) { this.logger = logger; } } const rapor = new RaporServisi(consoleLog); Bağımlılık constructor'da enjekte edilir. En yaygın ve güvenli DI yöntemidir
Setter Injection
class KullaniciAyarlari { setBildirimServisi(servis) { this.bildirimci = servis; } } ayarlar.setBildirimServisi(bildirimServisi); Bağımlılık setter metodu ile enjekte edilir. İsteğe bağlı bağımlılıklar için idealdir
Method Injection
class DosyaIsleyici { okuVeIsle(dosyaYolu, hataKaydedici) { // bağımlılık metoda parametre olarak } } isleyici.okuVeIsle(dosyaYolu, logger); Bağımlılık metod parametresi olarak geçirilir. Metod çağrısı sırasında sağlanır
CommonJS (Node.js)
module.exports
module.exports = { topla: topla, PI: PI }; Birden fazla üyeyi dışa aktarır. Node.js'te yaygın kullanılan yöntemdir
require()
const matematik = require('./math.js'); const sonuc = matematik.topla(10, 5); Modülü senkron olarak yükler. Dosya sistemi okuma işlemi bloklar
exports (Kısa Yol)
exports.topla = topla; exports.PI = PI; module.exports'un kısa yolu. Aynı işlevi görür ancak daha kısa yazılır
AMD (Asynchronous Module Definition)
define() (Basit)
define(function() { return { topla: function(a, b) { return a + b; } }; }); Bağımlılıksız modül tanımlar. Kendi başına çalışan modüller için kullanılır
define() (Bağımlılıklı)
define(['math', 'logger'], function(math, logger) { return { hesapla: function(x) { logger.log('Hesaplama yapılıyor'); return math.topla(x, 10); } }; }); Bağımlılıklarla modül tanımlar. Bağımlılıklar yüklendikten sonra modül çalışır
require() (AMD)
require(['calc'], function(calc) { const sonuc = calc.topla(10, 20); console.log(sonuc); }); Modülü asenkron olarak yükler. Tarayıcıda non-blocking yükleme sağlar
IIFE ve Module Pattern
IIFE (Geleneksel)
(function() { var sayac = 0; console.log("Hemen çalışır"); })(); Anında yürütülen fonksiyon ifadesi. Global scope'u kirletmeden kod çalıştırır
Module Pattern
var GecisModul = (function() { var _sayac = 0; // Private return { artir: function() { _sayac++; }, guncelDeger: function() { return _sayac; } }; })(); Public/private kapsülleme sağlar. Dışarıdan erişilemeyen özel değişkenler oluşturur
Revealing Module Pattern
var RaporModulu = (function() { function _hesapla() { return Math.random(); } function _disaAktar(format) { /* ... */ } return { exportEt: _disaAktar, tipi: _raporTipi }; })(); İç fonksiyonları açığa çıkarır. Daha okunabilir ve bakımı kolay kod yapısı sağlar
IoC/DI Konteynerleri
Bağımlılık Kaydı
konteyner.kaydet('Logger', ConsoleLogger); konteyner.kaydet('RaporServisi', RaporServisi); Soyutlama ve somut sınıf eşleştirmesi. Konteynere bağımlılık kaydı yapar
Bağımlılık Çözümleme
const rapor = konteyner.get('RaporServisi'); // Konteyner otomatik olarak logger'ı enjekte eder Otomatik bağımlılık grafiği çözümü. Tüm bağımlılıklar otomatik olarak enjekte edilir
Yaşam Döngüsü (Singleton)
konteyner.kaydet('DBBaglantisi', DB, { lifecycle: 'singleton' }); Uygulama genelinde tek örnek. Tüm istekler aynı instance'ı kullanır
Yaşam Döngüsü (Transient)
konteyner.kaydet('Rapor', Rapor, { lifecycle: 'transient' }); Her istekte yeni örnek oluşturur. Her çağrıda farklı bir instance döner

Öğrenme Yolu

JavaScript öğrenme yolculuğunuzda neredesiniz?

İlerleme
69%
12 Tamamlandı 18 Toplam
Giriş sayfası dahil edilmedi

Bu bölüm, JavaScript öğrenme yolculuğunuzdaki ilerlemenizi görselleştirir. Aşağıda göreceğiniz adımlar, konular arasındaki mantıksal sıralamayı ve öğrenme akışını temsil eder. Tamamlanan konular mavi tonlarda gösterilir ve üzerinde bir onay işareti bulunur. Aktif konu, şu anda üzerinde çalıştığınız bölümdür ve parlak mavi renkle vurgulanır. Sonraki adımlar ise henüz tamamlanmamış konuları gösterir ve daha soluk tonlarda görüntülenir.

Her adım arasındaki oklar, öğrenme sırasını ve konular arasındaki bağlantıyı gösterir. Bu yapı, hangi konuları tamamladığınızı, hangi konuda olduğunuzu ve sıradaki adımlarınızı net bir şekilde görmenizi sağlar.

Tamamlandı 1

JavaScript Giriş

JavaScript'e giriş ve temel kavramlar

Tamamlandı 2

Değişkenler

var, let, const ve scope kavramları

Tamamlandı 3

Veri Tipleri

JavaScript'te temel veri tipleri ve kullanımları

Tamamlandı 4

Operatörler

Aritmetik, mantıksal ve karşılaştırma operatörleri

Tamamlandı 5

If-Else

Koşullu yürütme ve karar yapıları

Tamamlandı 6

Switch-Case

Çoklu koşul kontrolü ve case yapısı

Tamamlandı 7

While

While ve Do-While döngüleri

Tamamlandı 8

For

For, For...of ve For...in döngüleri

Tamamlandı 9

Diziler (Arrays)

Dizi oluşturma, manipülasyon ve metodları

Tamamlandı 10

Functions

Fonksiyon tanımlama, parametreler ve return

Tamamlandı 11

Objects

Nesne oluşturma, özellikler ve metodlar

Tamamlandı 12

DOM

Document Object Model ve DOM manipülasyonu

Tamamlandı 13

Class

ES6 Class yapısı ve kalıtım

Aktif 14

Modülerlik ve Kod Organizasyonu

ES Modülleri, Bağımlılık Enjeksiyonu ve IoC Konteynerleri

Sonraki 15

Performance ve Memory

Performans optimizasyonu ve bellek yönetimi

Sonraki 16

Asenkron Programlama

Promise, async/await ve JSON işlemleri