Bu ders için video bulunmamaktadır.

Bu derse başlamak veya ilerlemenizi kaydetmek için lütfen giriş yapın veya kayıt olun.

Ders İçeriği

Giriş: Modüler Programlama

Modern JavaScript uygulamaları giderek daha karmaşık hale gelmektedir. Büyük uygulamaları yönetilebilir kılmak için, kodu daha küçük, bağımsız ve yeniden kullanılabilir parçalara bölmek önemlidir. Bu yaklaşım, modüler programlama olarak bilinir.

JavaScript'te modüller, kodunuzu mantıksal birimler halinde organize etmenize, bağımlılıkları yönetmenize ve kodun yeniden kullanılabilirliğini artırmanıza olanak tanır. Modüller sayesinde:

  • Kodunuzu daha küçük, yönetilebilir parçalara bölebilirsiniz
  • Bağımlılıkları açıkça belirtebilirsiniz
  • Değişken ve fonksiyon isim çakışmalarını önleyebilirsiniz (kapsam yönetimi)
  • Kodunuzu daha kolay test edebilirsiniz
  • Kodunuzu farklı projelerde yeniden kullanabilirsiniz

Bu derste, JavaScript'te modüler programlamanın temellerini, farklı modül sistemlerini ve modern JavaScript uygulamalarında modüllerin nasıl kullanıldığını öğreneceğiz.

JavaScript'te Modül Sistemlerinin Evrimi

JavaScript, başlangıçta modül sistemi olmadan tasarlanmıştı. Zaman içinde, geliştiriciler çeşitli modül sistemleri ve desenler geliştirdiler. İşte JavaScript modül sistemlerinin kısa bir tarihçesi:

1. IIFE (Immediately Invoked Function Expression)

İlk modül deseni, hemen çağrılan fonksiyon ifadeleri (IIFE) kullanılarak oluşturuldu. Bu, değişkenleri global kapsamdan izole etmek için kullanılan bir tekniktir.

iife_module.js
// IIFE ile basit bir modül
var HesapModulu = (function() {
    // Özel değişkenler (dışarıdan erişilemez)
    var vergiOrani = 0.18;
    
    // Özel fonksiyonlar
    function yuvarla(sayi) {
        return Math.round(sayi * 100) / 100;
    }
    
    // Dışa açılan API (public interface)
    return {
        kdvHesapla: function(fiyat) {
            return yuvarla(fiyat * vergiOrani);
        },
        toplamFiyatHesapla: function(fiyat) {
            return yuvarla(fiyat + this.kdvHesapla(fiyat));
        }
    };
})();

// Modülü kullanma
console.log(HesapModulu.kdvHesapla(100)); // 18
console.log(HesapModulu.toplamFiyatHesapla(100)); // 118

// Özel değişkenlere ve fonksiyonlara erişilemez
console.log(HesapModulu.vergiOrani); // undefined
console.log(HesapModulu.yuvarla); // undefined

2. CommonJS

Node.js'in yükselişiyle birlikte, CommonJS modül sistemi popüler hale geldi. Bu sistem, require() ve module.exports kullanarak modülleri yönetir.

hesap.js (CommonJS)
// Özel değişkenler
const vergiOrani = 0.18;

// Özel fonksiyonlar
function yuvarla(sayi) {
    return Math.round(sayi * 100) / 100;
}

// Dışa aktarılan fonksiyonlar
function kdvHesapla(fiyat) {
    return yuvarla(fiyat * vergiOrani);
}

function toplamFiyatHesapla(fiyat) {
    return yuvarla(fiyat + kdvHesapla(fiyat));
}

// Dışa aktarma (export)
module.exports = {
    kdvHesapla,
    toplamFiyatHesapla
};
app.js (CommonJS)
// Modülü içe aktarma (import)
const hesapModulu = require('./hesap.js');

// Modülü kullanma
console.log(hesapModulu.kdvHesapla(100)); // 18
console.log(hesapModulu.toplamFiyatHesapla(100)); // 118

3. AMD (Asynchronous Module Definition)

Tarayıcılar için geliştirilen AMD, modüllerin eşzamansız olarak yüklenmesini sağlar. RequireJS, bu formatın en popüler uygulamasıdır.

hesap.js (AMD)
// AMD modül tanımı
define([], function() {
    // Özel değişkenler
    const vergiOrani = 0.18;
    
    // Özel fonksiyonlar
    function yuvarla(sayi) {
        return Math.round(sayi * 100) / 100;
    }
    
    // Dışa aktarılan API
    return {
        kdvHesapla: function(fiyat) {
            return yuvarla(fiyat * vergiOrani);
        },
        toplamFiyatHesapla: function(fiyat) {
            return yuvarla(fiyat + this.kdvHesapla(fiyat));
        }
    };
});
app.js (AMD)
// AMD modülünü kullanma
require(['hesap'], function(hesapModulu) {
    console.log(hesapModulu.kdvHesapla(100)); // 18
    console.log(hesapModulu.toplamFiyatHesapla(100)); // 118
});

4. UMD (Universal Module Definition)

UMD, hem CommonJS hem de AMD ile uyumlu çalışabilen bir modül desenidir. Böylece, aynı kod hem Node.js hem de tarayıcılarda çalışabilir.

hesap.js (UMD)
// UMD modül deseni
(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node. CommonJS ortamı.
        module.exports = factory();
    } else {
        // Tarayıcı globals (root is window)
        root.HesapModulu = factory();
    }
}(typeof self !== 'undefined' ? self : this, function() {
    // Modül kodunuz burada
    const vergiOrani = 0.18;
    
    function yuvarla(sayi) {
        return Math.round(sayi * 100) / 100;
    }
    
    return {
        kdvHesapla: function(fiyat) {
            return yuvarla(fiyat * vergiOrani);
        },
        toplamFiyatHesapla: function(fiyat) {
            return yuvarla(fiyat + this.kdvHesapla(fiyat));
        }
    };
}));

5. ES Modules (ECMAScript Modules)

ES6 (ES2015) ile birlikte, JavaScript'e resmi bir modül sistemi eklendi: ES Modules. Bu, modern JavaScript'in standart modül sistemidir ve hem tarayıcılarda hem de Node.js'de desteklenir.

hesap.js (ES Modules)
// Özel değişkenler
const vergiOrani = 0.18;

// Özel fonksiyonlar
function yuvarla(sayi) {
    return Math.round(sayi * 100) / 100;
}

// Dışa aktarılan fonksiyonlar
export function kdvHesapla(fiyat) {
    return yuvarla(fiyat * vergiOrani);
}

export function toplamFiyatHesapla(fiyat) {
    return yuvarla(fiyat + kdvHesapla(fiyat));
}

// Varsayılan dışa aktarma (opsiyonel)
export default {
    kdvHesapla,
    toplamFiyatHesapla
};
app.js (ES Modules)
// İsimli içe aktarmalar
import { kdvHesapla, toplamFiyatHesapla } from './hesap.js';

console.log(kdvHesapla(100)); // 18
console.log(toplamFiyatHesapla(100)); // 118

// Varsayılan içe aktarma
import HesapModulu from './hesap.js';

console.log(HesapModulu.kdvHesapla(100)); // 18
console.log(HesapModulu.toplamFiyatHesapla(100)); // 118

// Tüm dışa aktarılanları bir nesne olarak içe aktarma
import * as Hesap from './hesap.js';

console.log(Hesap.kdvHesapla(100)); // 18
console.log(Hesap.toplamFiyatHesapla(100)); // 118
console.log(Hesap.default.kdvHesapla(100)); // 18

ES Modules (ESM) Detaylı İnceleme

ES Modules, modern JavaScript'in standart modül sistemidir ve şu anda en yaygın kullanılan modül sistemidir. Bu bölümde, ES Modules'ın temel özelliklerini ve kullanım şekillerini detaylı olarak inceleyeceğiz.

1. Modül Tanımlama ve Kullanma

ES Modules'da, her JavaScript dosyası bir modüldür. Modüller, export anahtar kelimesi ile değişkenleri, fonksiyonları veya sınıfları dışa aktarır ve import anahtar kelimesi ile bunları içe aktarır.

ES Modules Temel Yapısı

math.js

export function add(a, b) {...}

export function subtract(a, b) {...}

app.js

import { add, subtract } from './math.js';

add(5, 3); // 8

2. Dışa Aktarma (Export) Türleri

ES Modules'da iki tür dışa aktarma vardır: isimli (named) ve varsayılan (default).

İsimli Dışa Aktarmalar (Named Exports)

math.js
// Yöntem 1: Doğrudan dışa aktarma
export const PI = 3.14159;
export function add(a, b) {
    return a + b;
}
export function subtract(a, b) {
    return a - b;
}

// Yöntem 2: Tanımla ve sonra dışa aktar
const multiply = (a, b) => a * b;
const divide = (a, b) => a / b;

export { multiply, divide };

Varsayılan Dışa Aktarma (Default Export)

Her modülde yalnızca bir varsayılan dışa aktarma olabilir.

calculator.js
// Yöntem 1: Doğrudan varsayılan dışa aktarma
export default class Calculator {
    add(a, b) {
        return a + b;
    }
    
    subtract(a, b) {
        return a - b;
    }
}

// Yöntem 2: Tanımla ve sonra varsayılan olarak dışa aktar
const calculator = {
    multiply: (a, b) => a * b,
    divide: (a, b) => a / b
};

export default calculator;

İsimli ve Varsayılan Dışa Aktarmaları Birlikte Kullanma

utils.js
// İsimli dışa aktarmalar
export function formatDate(date) {
    return date.toLocaleDateString();
}

export function formatCurrency(amount) {
    return `₺${amount.toFixed(2)}`;
}

// Varsayılan dışa aktarma
export default class Utils {
    static generateId() {
        return Math.random().toString(36).substr(2, 9);
    }
    
    static capitalize(str) {
        return str.charAt(0).toUpperCase() + str.slice(1);
    }
}

3. İçe Aktarma (Import) Türleri

ES Modules'da, dışa aktarılan değerleri farklı şekillerde içe aktarabilirsiniz.

İsimli İçe Aktarmalar (Named Imports)

app.js
// Belirli isimli dışa aktarmaları içe aktarma
import { add, subtract, PI } from './math.js';

console.log(add(5, 3)); // 8
console.log(subtract(10, 4)); // 6
console.log(PI); // 3.14159

// İçe aktarırken yeniden adlandırma
import { add as topla, subtract as cikar } from './math.js';

console.log(topla(5, 3)); // 8
console.log(cikar(10, 4)); // 6

Varsayılan İçe Aktarma (Default Import)

app.js
// Varsayılan dışa aktarmayı içe aktarma
import Calculator from './calculator.js';

const calc = new Calculator();
console.log(calc.add(5, 3)); // 8
console.log(calc.subtract(10, 4)); // 6

// Varsayılan dışa aktarmayı istediğiniz isimle içe aktarabilirsiniz
import HesapMakinesi from './calculator.js';

const hesap = new HesapMakinesi();
console.log(hesap.add(5, 3)); // 8

İsimli ve Varsayılan İçe Aktarmaları Birlikte Kullanma

app.js
// Hem varsayılan hem de isimli dışa aktarmaları içe aktarma
import Utils, { formatDate, formatCurrency } from './utils.js';

console.log(formatDate(new Date())); // "5/27/2025"
console.log(formatCurrency(99.99)); // "₺99.99"
console.log(Utils.generateId()); // "f7g3h9j2k"
console.log(Utils.capitalize('merhaba')); // "Merhaba"

Tüm İçe Aktarmalar (Namespace Import)

app.js
// Tüm dışa aktarmaları bir nesne olarak içe aktarma
import * as MathUtils from './math.js';

console.log(MathUtils.add(5, 3)); // 8
console.log(MathUtils.subtract(10, 4)); // 6
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.multiply(2, 3)); // 6
console.log(MathUtils.divide(10, 2)); // 5

4. Modül Yeniden Dışa Aktarma (Re-exporting)

Bazen, bir modülden içe aktardığınız değerleri başka bir modülden dışa aktarmak isteyebilirsiniz. Buna "yeniden dışa aktarma" (re-exporting) denir.

math.js
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
utils.js
export function formatDate(date) { return date.toLocaleDateString(); }
export function formatCurrency(amount) { return `₺${amount.toFixed(2)}`; }
index.js
// math.js'den tüm dışa aktarmaları yeniden dışa aktar
export * from './math.js';

// utils.js'den belirli dışa aktarmaları yeniden dışa aktar
export { formatDate, formatCurrency } from './utils.js';

// Yeniden adlandırarak yeniden dışa aktarma
export { add as topla, subtract as cikar } from './math.js';

// Kendi dışa aktarmalarımız
export const VERSION = '1.0.0';
export function greet(name) {
    return `Merhaba, ${name}!`;
}
app.js
// index.js'den içe aktarma
import { PI, add, topla, formatDate, VERSION, greet } from './index.js';

console.log(PI); // 3.14159
console.log(add(5, 3)); // 8
console.log(topla(5, 3)); // 8 (add ile aynı)
console.log(formatDate(new Date())); // "5/27/2025"
console.log(VERSION); // "1.0.0"
console.log(greet('Ahmet')); // "Merhaba, Ahmet!"

5. Dinamik İçe Aktarma (Dynamic Import)

ES Modules, statik içe aktarmanın yanı sıra, dinamik içe aktarmayı da destekler. Bu, modülleri ihtiyaç duyulduğunda eşzamansız olarak yüklemenize olanak tanır.

app.js
// Statik içe aktarma (dosyanın en üstünde)
import { add } from './math.js';

// Dinamik içe aktarma (ihtiyaç duyulduğunda)
async function loadMathModule() {
    try {
        // import() bir Promise döndürür
        const mathModule = await import('./math.js');
        
        console.log(mathModule.add(5, 3)); // 8
        console.log(mathModule.subtract(10, 4)); // 6
        console.log(mathModule.PI); // 3.14159
    } catch (error) {
        console.error('Modül yüklenirken hata oluştu:', error);
    }
}

// Kullanıcı bir butona tıkladığında modülü yükle
document.getElementById('loadButton').addEventListener('click', loadMathModule);

// Koşullu içe aktarma
async function conditionalImport(condition) {
    if (condition) {
        const { formatDate } = await import('./utils.js');
        console.log(formatDate(new Date()));
    } else {
        const { add } = await import('./math.js');
        console.log(add(5, 3));
    }
}

Not: Dinamik içe aktarma, kod bölme (code splitting) ve tembel yükleme (lazy loading) için çok kullanışlıdır. Özellikle büyük uygulamalarda, başlangıçta tüm kodu yüklemek yerine, ihtiyaç duyulduğunda belirli modülleri yükleyerek performansı artırabilirsiniz.

Tarayıcılarda ES Modules Kullanımı

Modern tarayıcılar, ES Modules'ı doğrudan destekler. Bir script'i modül olarak yüklemek için, <script> etiketine type="module" özniteliği eklemeniz yeterlidir.

index.html
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ES Modules Örneği</title>
</head>
<body>
    <h1>ES Modules Örneği</h1>
    <button id="calculateBtn">Hesapla</button>
    <div id="result"></div>
    
    <!-- Modül olarak script yükleme -->
    <script type="module">
        // Doğrudan HTML içinde modül kullanımı
        import { add, subtract } from './math.js';
        
        document.getElementById('calculateBtn').addEventListener('click', () => {
            const result = add(10, 5);
            document.getElementById('result').textContent = `Sonuç: ${result}`;
        });
    </script>
    
    <!-- Harici bir modül dosyası yükleme -->
    <script type="module" src="app.js"></script>
</body>
</html>

Tarayıcılarda ES Modules Kullanırken Dikkat Edilmesi Gerekenler

  • CORS (Cross-Origin Resource Sharing): ES Modules, CORS politikalarına tabidir. Yerel dosya sisteminden modülleri yüklemek için bir web sunucusu kullanmanız gerekebilir.
  • Uzantılar: Tarayıcılarda, içe aktarma yollarında .js uzantısını belirtmeniz gerekir.
  • Katı Mod: Tüm ES modülleri otomatik olarak "strict mode" altında çalışır.
  • Eşzamansız Yükleme: type="module" ile yüklenen scriptler varsayılan olarak eşzamansızdır (async).
  • Tek Kez Yürütme: Aynı modül birden fazla kez içe aktarılsa bile, yalnızca bir kez yürütülür.

Uyarı: Eski tarayıcılar ES Modules'ı desteklemeyebilir. Uyumluluk için, bir derleme aracı (Webpack, Rollup, Parcel vb.) veya bir transpiler (Babel) kullanabilirsiniz.

Node.js'de ES Modules Kullanımı

Node.js, geleneksel olarak CommonJS modül sistemini kullanır, ancak Node.js 13.2.0 ve sonraki sürümlerde ES Modules desteği de eklenmiştir. Node.js'de ES Modules kullanmanın birkaç yolu vardır:

1. .mjs Uzantısı Kullanma

Dosya uzantısını .mjs olarak değiştirerek, Node.js'e bu dosyanın bir ES modülü olduğunu belirtebilirsiniz.

math.mjs
export function add(a, b) {
    return a + b;
}

export function subtract(a, b) {
    return a - b;
}
app.mjs
import { add, subtract } from './math.mjs';

console.log(add(5, 3)); // 8
console.log(subtract(10, 4)); // 6

2. package.json'da "type": "module" Belirtme

Projenizin package.json dosyasında "type": "module" belirterek, tüm .js dosyalarının ES modülü olarak değerlendirilmesini sağlayabilirsiniz.

package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "type": "module",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  }
}
math.js
export function add(a, b) {
    return a + b;
}

export function subtract(a, b) {
    return a - b;
}
app.js
import { add, subtract } from './math.js';

console.log(add(5, 3)); // 8
console.log(subtract(10, 4)); // 6

Node.js'de ES Modules Kullanırken Dikkat Edilmesi Gerekenler

  • __dirname ve __filename: ES Modules'da __dirname ve __filename global değişkenleri bulunmaz. Bunun yerine, import.meta.url kullanabilirsiniz.
  • require(): ES Modules'da require() fonksiyonu kullanılamaz. Bunun yerine, import ifadesini veya dinamik import() fonksiyonunu kullanmalısınız.
  • Uzantılar: Node.js'de ES Modules kullanırken, içe aktarma yollarında dosya uzantılarını belirtmeniz gerekir.
utils.js (ES Modules)
// __dirname ve __filename yerine
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

console.log('Dosya yolu:', __filename);
console.log('Dizin yolu:', __dirname);

// JSON dosyası okuma
import { readFileSync } from 'fs';
const config = JSON.parse(readFileSync('./config.json', 'utf8'));

export function getConfig() {
    return config;
}

Modül Paketleyiciler (Bundlers)

Modern web geliştirmede, modül paketleyiciler (bundlers) yaygın olarak kullanılır. Bu araçlar, modülleri ve bağımlılıklarını tek bir dosyada birleştirir, böylece tarayıcıda daha verimli bir şekilde yüklenebilirler.

Popüler Modül Paketleyiciler

  • Webpack: En popüler ve güçlü modül paketleyici. Sadece JavaScript değil, CSS, resimler ve diğer varlıkları da işleyebilir.
  • Rollup: Özellikle kütüphaneler için optimize edilmiş, "tree-shaking" özelliği ile kullanılmayan kodu elemede etkili bir paketleyici.
  • Parcel: Sıfır yapılandırma gerektiren, kullanımı kolay bir paketleyici.
  • esbuild: Go ile yazılmış, çok hızlı bir JavaScript paketleyici ve minifier.
  • Vite: Modern web projeleri için hızlı bir geliştirme ortamı ve derleme aracı.

Webpack Örneği

Webpack, en yaygın kullanılan modül paketleyicidir. İşte basit bir Webpack yapılandırması:

webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/app.js', // Giriş noktası
  output: {
    filename: 'bundle.js', // Çıktı dosyası
    path: path.resolve(__dirname, 'dist') // Çıktı dizini
  },
  mode: 'development', // veya 'production'
  module: {
    rules: [
      {
        test: /\.js$/, // .js dosyalarını işle
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader', // Babel ile ES6+ kodunu dönüştür
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};

Webpack ile bir projeyi derlemek için:

Terminal
# Webpack'i yükle
npm install webpack webpack-cli --save-dev

# Babel ve ilgili paketleri yükle
npm install @babel/core babel-loader @babel/preset-env --save-dev

# Projeyi derle
npx webpack

Modül Paketleyicilerin Avantajları

  • Kod Bölme (Code Splitting): Uygulamanızı daha küçük parçalara bölerek, ihtiyaç duyulduğunda yüklenmesini sağlar.
  • Tree Shaking: Kullanılmayan kodu elemek için statik analiz kullanır.
  • Varlık Optimizasyonu: Resimler, CSS ve diğer varlıkları optimize eder.
  • Dönüştürücüler (Transformers): Babel gibi araçlarla modern JavaScript'i eski tarayıcılar için uyumlu hale getirir.
  • Geliştirme Araçları: Hot Module Replacement (HMR) gibi geliştirme deneyimini iyileştiren özellikler sunar.

Alıştırmalar

  1. Bir hesap makinesi modülü oluşturun. Modül, temel matematik işlemlerini (toplama, çıkarma, çarpma, bölme) ve bazı ileri işlemleri (karekök, üs alma) içermelidir. Modülü ES Modules sözdizimi ile yazın.
  2. Bir para birimi dönüştürücü modülü oluşturun. Modül, farklı para birimleri arasında dönüşüm yapabilmelidir (TL, USD, EUR, GBP). Modülü varsayılan ve isimli dışa aktarmalar kullanarak yazın.
  3. Bir tarih işleme modülü oluşturun. Modül, tarih formatlama, tarih aralığı hesaplama ve tarih karşılaştırma gibi işlevler içermelidir. Modülü CommonJS sözdizimi ile yazın ve sonra ES Modules'a dönüştürün.
  4. Bir HTML sayfası oluşturun ve type="module" kullanarak bir JavaScript modülünü yükleyin. Modül, sayfadaki DOM elemanlarını manipüle etmelidir.
  5. Bir ana modül oluşturun ve diğer modüllerden belirli fonksiyonları içe aktarıp yeniden dışa aktarın (re-export). Sonra, bu ana modülü başka bir dosyadan içe aktarın ve kullanın.

Bu derste, JavaScript'te modüler programlamanın temellerini ve farklı modül sistemlerini inceledik:

  • Modüler Programlama: Kodu daha küçük, yönetilebilir ve yeniden kullanılabilir parçalara bölme yaklaşımı.
  • Modül Sistemlerinin Evrimi: IIFE, CommonJS, AMD, UMD ve ES Modules gibi farklı modül sistemleri ve desenleri.
  • ES Modules (ESM): Modern JavaScript'in standart modül sistemi. export ve import anahtar kelimeleri ile kullanılır.
  • Dışa Aktarma Türleri: İsimli (named) ve varsayılan (default) dışa aktarmalar.
  • İçe Aktarma Türleri: İsimli, varsayılan ve namespace içe aktarmalar.
  • Dinamik İçe Aktarma: import() fonksiyonu ile eşzamansız modül yükleme.
  • Tarayıcılarda ES Modules: <script type="module"> ile modül kullanımı.
  • Node.js'de ES Modules: .mjs uzantısı veya "type": "module" ile modül kullanımı.
  • Modül Paketleyiciler: Webpack, Rollup, Parcel gibi araçlarla modülleri paketleme ve optimize etme.

Modüller, modern JavaScript uygulamalarının temel yapı taşlarıdır. Kodunuzu modüller halinde organize etmek, daha sürdürülebilir, test edilebilir ve ölçeklenebilir uygulamalar geliştirmenize yardımcı olur.

Bir sonraki derste, modern JavaScript'in diğer önemli özelliklerinden biri olan sınıflar (classes) ve nesne yönelimli programlama konularını inceleyeceğiz.