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.
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.
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'
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.
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.
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.
Bağımlılıkların sınıfın constructor metoduna parametre olarak geçirilmesi. En yaygın ve güvenli DI yöntemidir.
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.
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.
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.
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.
Node.js için tasarlanmış modül sistemi. require() ve module.exports
kullanır.
Senkron yükleme yapar.
Tarayıcılar için tasarlanmış asenkron modül sistemi. define() ve require()
kullanır.
Non-blocking yükleme sağlar.
Immediately Invoked Function Expression. Tanımlandığı anda hemen çalışan fonksiyon ifadesi. Kapsam izolasyonu sağlar ve global kirliliği önler.
IIFE kullanarak public/private kapsülleme sağlayan desen. Closure ile iç durumu korur ve kontrollü bir API sunar.
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.
Kullanılmayan kodu (dead code) nihai paketten çıkarma optimizasyonu. Statik analiz gerektirir, ES Modülleri ile mümkündür.
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.
İ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.
Veri ve işlevlerin bir arada tutulması ve dış dünyadan gizlenmesi. Module Pattern ve ES Modülleri ile sağlanır.
Modüller arasındaki bağımlılık ilişkilerinin oluşturduğu grafik yapısı. DI Konteynerleri bu grafiği otomatik çözer.
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.
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.
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.
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.
ES Modülleri (ESM - ECMAScript Modules) Modern Standart
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 DevrimiESM'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ıkES 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 OrganizasyonuSonuç 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
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 ShakingStatik 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 StandartBloke 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.
|
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.
|
<!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";
<!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;
<!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)
Bağımlılık Enjeksiyonu (DI) Mimaride Esneklik
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 İzolasyonDI'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
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ılabilirlikSorumlulukları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ımSonuç 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?
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çlarHı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ğrulamaTest 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, 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üzlerSomut 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 MaliyetiEsnek 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
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 AdaptasyonBir 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önetimiYeniden 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.
|
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
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) EnjeksiyonuZorunlu 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?
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 BelgelemeAçı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şaSonuç 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.
<!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?
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üvenlikDurum 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.
<!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?
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 EsneklikKaynak 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 MimariSonuç 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.
<!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);
});
İleri Kavramlar: IoC/DI Konteynerleri Detaylı Konu Açıklamaları
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ümlemeKonteynerlerin 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önetimiIoC 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 MimariTü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
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ımBir 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) StratejileriKonteynerlerin 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.
<!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.
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.
Modülerliğin Tarihi Kökleri ve Kapsam Yönetimi Detaylı Konu Açıklamaları
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 GizlemeNesne 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
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, 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ğiSü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 DevrimiAçığ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.
<!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.
<!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"]
Bağımlılık Yönetiminin Evrimi (ES6 Öncesi) Detaylı Konu Açıklamaları
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ıklarES6 ö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ı StandartlarBu 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
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.exportsCommonJS'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.<!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)
AMD, adından da anlaşılacağı üzere modül yükleme sürecini asenkron olarak yönetmek için tasarlanmıştır.
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.
<!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.
Öğ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
Kod Örnekleri İstatistikleri
Bu sayfadaki tüm kod örneklerinin seviye dağılımı
HTML Seviye Dağılımı
CSS Seviye Dağılımı
JavaScript Seviye Dağılımı
Kod Dosyaları
Bu sayfadaki tüm kod dosyalarını dil ve seviyeye göre filtreleyin
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
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
import { topla, PI } from './math.js';
Belirli üyeleri içe aktarır. Süslü parantez içinde isimleri
belirtilir
import baglanti from './modül.js';
Varsayılan üyeyi içe aktarır. Süslü parantez kullanılmaz, isim
serbesttir
import * as Matematik from './math.js';
Tüm üyeleri bir nesne altında toplar. Nokta notasyonu ile
erişilir
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
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
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
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
module.exports = {
topla: topla,
PI: PI
};
Birden fazla üyeyi dışa aktarır. Node.js'te yaygın kullanılan
yöntemdir
const matematik = require('./math.js');
const sonuc = matematik.topla(10, 5);
Modülü senkron olarak yükler. Dosya sistemi okuma işlemi
bloklar
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
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(['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(['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
(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
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
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
konteyner.kaydet('Logger', ConsoleLogger);
konteyner.kaydet('RaporServisi', RaporServisi);
Soyutlama ve somut sınıf eşleştirmesi. Konteynere bağımlılık kaydı
yapar
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
konteyner.kaydet('DBBaglantisi', DB, {
lifecycle: 'singleton'
});
Uygulama genelinde tek örnek. Tüm istekler aynı instance'ı
kullanır
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?
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.
Modülerlik ve Kod Organizasyonu
ES Modülleri, Bağımlılık Enjeksiyonu ve IoC Konteynerleri