OOP ve Fonksiyonel Programlama: Basit JavaScript Örnekleri
Programlama Paradigmaları
OOP ve Fonksiyonel Programlama: Basit JavaScript Örnekleri

OOP ve Fonksiyonel Programlama: Basit JavaScript Örnekleri
Programlama paradigmaları — özellikle nesne yönelimli programlama (OOP) ve fonksiyonel programlama — yazılım tasarımında farklı düşünme biçimleri sunar. Bu yazıda bu iki yaklaşımın temel ilkelerini, JavaScript içinde nasıl uygulandıklarını ve günlük problemlerde nasıl kullanılabileceklerini pratik örneklerle göstereceğim.
Temel kavramlar: Kısa tanımlar
Nesne yönelimli programlama (OOP): Veriyi ve işlemleri bir arada tutan nesneler etrafında modellenir; kapsülleme, kalıtım ve polimorfizm gibi kavramlara dayanır. JavaScript'teki OOP yaklaşımlarının açıklaması için ilgili referanslara bakılabilir.
Kaynak: OnlyJS — OOP açıklaması.
Fonksiyonel programlama (FP): Saf fonksiyonlar, değişmezlik (immutability) ve yan etkilerin sınırlandırılması gibi prensiplere dayalıdır. FP mantığı veri dönüşümleri ve fonksiyon kompozisyonunu öne çıkarır.
Kaynak: Clean Code Guy — Fonksiyonel Programlama vs OOP.
JavaScript'in rolü: JavaScript prototip tabanlı bir dil olmakla beraber hem sınıf-temelli (ES6 class sözdizimi) hem de fonksiyonel yaklaşımları destekleyecek esnekliktedir. Bu nedenle aynı projede her iki paradigmanın öğeleri bir arada kullanılabilir.
Kaynak: HasCoding — JavaScript'te OOP.
Hızlı karşılaştırma
| OOP | Fonksiyonel | |
|---|---|---|
| Temel fikir | Nesneler etrafında veri+davranış. | Saf fonksiyonlarla veri dönüşümleri. |
| Yan etkiler | Durum ve yan etkiler sıkça bulunur. | Yan etkiler sınırlandırılır; test etmesi kolaydır. |
| Uygun olduğu alanlar | Durumu ağır modeller, domain odaklı nesne tasarımları. | Veri dönüşümü, pipeline ve yüksek test edilebilirlik gerektiren mantık. |
JavaScript'te OOP: Basit örnekler ve açıklama
Aşağıda ES6 sınıf sözdizimi ile basit bir OOP örneği var. Sınıflar veri ve metotları bir arada gruplar.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Merhaba, benim adım ${this.name}.`;
}
}
const ali = new Person('Ali', 30);
ali.greet();
Bu örnekte Person nesnesi hem veriyi (name, age) hem de davranışı (greet metodu) içerir. JavaScript'te class sözdizimi aslında prototip temelli yapının sentaktik şekillendirmesidir; bu detaya ilişkin bilgiler için kaynaklara bakabilirsiniz.
Kaynak: HasCoding — JavaScript OOP.
Alternatif olarak klasik prototip tabanlı tanım şu şekildedir:
function PersonProto(name, age) {
this.name = name;
this.age = age;
}
PersonProto.prototype.greet = function() {
return 'Merhaba, benim adım ' + this.name + '.';
};
var ayse = new PersonProto('Ayşe', 25);
ayse.greet();
Prototip tabanlı yaklaşım, JavaScript'in altında yatan modelle daha birebir çalışmak isteyenler için açıklayıcıdır. Sınıflar bu modeli daha okunabilir bir sözdizimi ile kullanmayı kolaylaştırır.
JavaScript'te Fonksiyonel Programlama: Basit örnekler
Fonksiyonel programlamada küçük, saf (aynı giriş için hep aynı çıkışı veren) fonksiyonlar ve bunların birleşimi (composition) ön plandadır.
Basit bir saf fonksiyon örneği:
const add = (a, b) => a + b;
Dizi dönüşümleri için map/filter/reduce sık kullanılır:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
Yüksek mertebeden fonksiyon (higher-order function) örneği:
const makeMultiplier = factor => n => n * factor;
const double = makeMultiplier(2);
double(5); // 10
Değişmezlik (immutability) uygulamak için spread operatörü veya Object.assign gibi yöntemlerle yeni nesneler/array'ler oluşturulur:
const user = { name: 'Ali', age: 30 };
const updated = { ...user, age: 31 }; // orijinal user değişmez
Fonksiyonel yaklaşım, mantığın daha kolay test edilebilmesini ve beklenmeyen yan etkilerin azaltılmasını sağlar. Bu prensipler hakkında daha fazla okumak isterseniz ilgili karşılaştırma yazısına bakabilirsiniz.
Kaynak: Clean Code Guy — Fonksiyonel Programlama vs OOP.
Hangi yaklaşımı ne zaman seçmeli? Pratik rehber
- Durum-ağırlıklı domanlar: Karmaşık domain modelleri ve nesneler arası ilişkiler varsa OOP daha doğal bir modelleme sunabilir.
- Veri dönüşümleri ve pipeline'lar: Veri odaklı dönüşümler, raporlamalar veya fonksiyon zincirleme gerektiren işler için fonksiyonel stil daha uygun olabilir.
- Büyük ekipler: Tutarlı kod kuralları ve iyi tanımlanmış sınırlar (API'ler) olduğunda her iki yaklaşım da çalışır; genelde saf fonksiyonlar birim testleri kolaylaştırır, OOP ise domain kavramlarını kodda daha görünür kılar.
- Hibrit yaklaşım: Çoğu proje JavaScript ekosisteminde her iki paradigmayı karıştırır. Örneğin, veri dönüşüm mantığını fonksiyonel tutup, uygulama durumunu yönetmek için sınıfları veya framework yapısını kullanabilirsiniz.
Birleştirme stratejileri ve iyi uygulamalar (küçük checklist)
- Çekirdek iş mantığını mümkün olduğunca saf fonksiyonlarla yazın; yan etkileri kenarda toplayın.
- Mutasyon yerine yeni veri yapıları oluşturun (spread, concat, slice vs.).
- Sınıfları, veri + davranış mantığı net olduğunda kullanın; inheritance yerine composition tercih edin.
- Test yazmayı erken alışkanlık haline getirin; saf fonksiyonlar birim testlerini basitleştirir.
- Kodun okunabilirliğini korumak için kısa fonksiyonlar ve açık isimlendirme kullanın.
Adım adım uygulama alıştırmaları
- Basit Todo uygulaması: Model için sınıf (Todo, TodoList) oluşturun. Filtreleme, ekleme ve silme işlemlerini saf fonksiyonlarla yazın (ör. filter ile tamamlananları ayırma).
- Data pipeline: Bir kullanıcı listesini map/filter/reduce kullanarak dönüştürün; örneğin yaş ortalamasını hesaplayın ve 30'dan büyükleri listeleyin.
- Yüksek mertebeden fonksiyonlar: makeMultiplier gibi üretici fonksiyonlar yazın ve farklı davranışlar için kullanın.
- Refactor alıştırması: Küçük bir sınıf tabanlı kodu alıp fonksiyonel parçalara bölün; ardından her iki sürümü test edin ve davranışın aynı kaldığını doğrulayın.
Yaygın tuzaklar ve nasıl kaçınmalı
- Paylaşılan mutable state: Global veya paylaşılan nesnelerde doğrudan değişiklikler hatalara yol açar; mümkünse kopyalayarak değiştirin.
- map içinde yan etki: map yalnızca dönüşüm için kullanılmalı; içindeki yan etkiler kafa karıştırır.
- Aşırı kalıtım: Derin inheritance zincirleri yerine bileşen tabanlı (composition) yaklaşımlar tercih edilebilir.
- Okunabilirliği feda etme: Çok kısa ve gizemli arrow fonksiyonlar yerine açık isimlendirme tercih edin.
Sonuç
OOP ve fonksiyonel programlama, JavaScript içinde birbirini dışlamayan, farklı güçlü yönleri olan yaklaşımlardır. Küçük, saf fonksiyonlar ve immutability test edilebilirliği artırırken; sınıf ve nesne temelli modelleme karmaşık domainleri daha doğal ifade edebilir. Pratikte en iyi sonuçlar genellikle iki paradigmanın bilinçli bir birleşimiyle elde edilir. Aşağıdaki kaynaklar başlangıç ve derinleşme için uygundur.