JavaScript’te daha iyi koşul yazmak için 5 öneri

JavaScript ile çalışırken bir çok koşul yazmamız gerekiyor. Daha temiz, belki daha iyi koşullar için 5 önerim var.

1. Birden fazla kriter için Array.includes kullanın #

Aşağıdaki örneği inceleyelim:

// koşul
function test(meyve) {
if (meyve == 'çilek' || meyve == 'elma') {
console.log('kırmızı');
}
}

İlk bakışta örnek güzel görünüyor. Fakat daha fazla kırmızı meyve için devamında vişne diye koşulu devam ettirmemiz mi gerekiyor? Koşulu || ile devam mı ettireceğiz?

Koşulu Array.includes kullanarak tekrar yazalım. (Bkz: Array.includes)

Kırmızı meyvelerin bulunduğu bir dizi oluşturduk. Bu diziyi koşul olarak Array.includes ile kontrol ettik. Bununla birlikte çok daha temiz ve genişletilebilir oldu.

2. İç içe koşul yazma, fonksiyonu erken bitir #

Önceki maddedeki örneğe iki koşul daha ekleyelim.

function test(meyve, adet) {
const kirmiziMeyveler = ['elma', 'çilek', 'vişne'];

// 1. koşul: meyve parametresi tanımlı olmalı
if (meyve) {
// 2. koşul: kırmızı olmalı
if (kirmiziMeyveler.includes(meyve)) {
console.log('kırmızı');

// 3. koşul: eğer çoksa
if (adet > 10) {
console.log('çok fazla');
}
}
} else {
throw new Error('meyve tanımlı değil!');
}
}

// fonksiyonu çalıştır
test(null); // hata: meyve tanımlı değil!
test('elma'); // çıktı: kırmızı
test('elma', 11); // çıktı: kırmızı, çok fazla

Yukarıdaki koda göre:

Kişisel olarak uyguladığım bir kural, geçersiz koşulu erken döndür.

function test(meyve, adet) {
const kirmiziMeyveler = ['elma', 'çilek', 'vişne'];

// 1. koşul: meyve parametresi tanımlı olmalı
if (!meyve) throw new Error('meyve tanımlı değil!');

// 2. koşul: kırmızı olmalı
if (kirmiziMeyveler.includes(meyve)) {
console.log('kırmızı');

// 3. koşul: eğer çoksa
if (adet > 10) {
console.log('çok fazla');
}
}
}

Bu kuralı uygulayıp bir seviye iç içe koşul yazmaktan kurtulduk. Bu yazım stili özellikle uzun ifadeler yazıyorsanız fazlasıyla işinize yarayacaktır.

if/else hell!

Koşulları tersine çevirip, iç içe yazma olayını daha da azaltabiliriz.

function test(meyve, adet) {
const kirmiziMeyveler = ['elma', 'çilek', 'vişne'];

if (!meyve) throw new Error('meyve tanımlı değil!'); // 1. koşul: hatayı erken fırlat
if (!kirmiziMeyveler.includes(meyve)) return; // 2. koşul: eğer meyve kırmızı değilse fonksiyonu atla

console.log('kırmızı');

// 3. koşul: eğer çoksa
if (adet > 10) {
console.log('çok fazla');
}
}

Önceki örneklerde “eğer mevye kırmızıysa” diye baktığımız koşulu tersine çevirdiğimizde (bkz: 2. koşul) artık iç içe yazılmış ifadelerimiz kalmıyor. Bu teknikle kodun daha fazla çalışmasına engel olup, hızlıca metodu durdurabiliyoruz.

Bu bir kural değil tabii ki. Fakat uygulayıp uygulamamak arasındaki karar için kendinize şu soruyu sorun: Kodun hangi hali daha okunabilir?

3. Parametrelere değer verin, Destructuring kullanın #

Muhtemelen aşağıdaki kod size tanıdık gelecektir. JavaScript ile çalışırken neredeyse her zaman tanımsız ya da boş değer kontrolü yapmamız ve değer yoksa atamamız gerekir.

function test(meyve, adet) {
if (!meyve) return;
const n = adet || 1; // Eğer adet tanımlı değilse 1 olarak tanımla

console.log(`Sepette ${n} ${meyve} var`);
}

// fonksiyonu çalıştır
test('muz'); // Sepette 1 muz var
test('elma', 2); // Sepette 2 elma var

Aslında parametrelere standart bir değer atarsak n değişkeninden kurtulabiliriz.

function test(meyve, adet = 1) { // Eğer adet tanımlı değilse 1 olarak tanımla
if (!meyve) return;
console.log(`Sepette ${adet} ${meyve} var`);
}

// fonksiyonu çalıştır
test('muz'); // Sepette 1 muz var
test('elma', 2); // Sepette 2 elma var

Çok daha basit değil mi? Bu özelliği tüm metod parametrelerinde kullanabiliriz. Mesela meyve parametresine de atama yapabilirdik:
function test(meyve = 'bilinmeyen', adet = 1)

Peki, meyve parametresi bi’ obje olsaydı? O zaman da standart bir değer verebilir miydik?

function test(meyve) {
// eğer tanımlıysa meyve ismini yazıyoruz
if (meyve && meyve.isim) {
console.log (meyve.isim);
} else {
console.log('tanımsız');
}
}

// fonksiyonu çalıştır
test(undefined); // tanımsız
test({ }); // tanımsız
test({ isim: 'elma', renk: 'kırmızı' }); // elma

Yukarıdaki örnekte; eğer meyve objesinde isim değişkeni tanımlıysa onu, değilse tanımsız yazmak istiyoruz. Daha fazla koşul yazmayıp, objenin içinde beklediğimiz değişkene standart bir değer atayabiliriz.

// destructuring assignment - objeden sadece isim alanını getir
// eğer tanımlı değilse boş obje tanımı {}
function test({isim} = {}) {
console.log (isim || 'tanımsız');
}

// fonksiyonu çalıştır
test(undefined); // tanımsız
test({ }); // tanımsız
test({ isim: 'elma', renk: 'kırmızı' }); // elma

Sadece isim değişkenine ihtiyacımız olduğu için parametre alanına {name} yazıp sadece obje içerisinden o değişkeni alabiliriz. Artık değişkeni meyve.isim olarak değil, direkt isim olarak kullanabiliriz.

Yukarıdaki kodda test({isim} = {}) olarak tanımlama nedenim, eğer tanımsız bir değer verilirse hata vermemesi. Çünkü test({isim}) olarak kullanırsanız, ve değer olarak undefined bir değişken gelirse (destructed parameter) is undefined hatası verecektir.

Eğer 3. parti kütüphaneler kullanıyorsanız boş/tanımsız kontrolünü daha kısa yoldan yapabilirsiniz.

Lodash kullanımına bir örnek:

// lodash kütüphanesini eklediğinizde _ değişkenine erişebilirsiniz
function test(meyve) {
console.log(_.get(meyve, 'isim', 'tanımsız'); // obje içerisindeki değişkeni getir, eğer yoksa değeri 'tanımsız' olarak tanımla
}

//test sonuçları
test(undefined); // tanımsız
test({ }); // tanımsız
test({ isim: 'elma', renk: 'kırmızı' }); // elma

4. Switch ifadesi yerine Object Literal kullanın #

Aşağıdaki örnekte meyveleri renklerine göre yazdırmak istiyoruz:

function test(renk) {
// renk bazlı meyveleri bulmak için switch/case kullanımı
switch (renk) {
case 'kırmızı':
return ['elma', 'çilek'];
case 'sarı':
return ['muz', 'ananas'];
case 'yeşil':
return ['üzüm', 'avokado'];
default:
return [];
}
}

// fonksiyonu çalıştır
test(null); // []
test('sarı'); // ['muz', 'ananas']

Yukarıdaki kod parçasında hata yok gibi görünüyor. Fakat oldukça ayrıntılı. Object literals olarak yazıldığında aynı sonuca çok daha temiz ulaşabiliriz.

// renk bazlı meyveleri bulmak için object literal kullanımı
const meyveler = {
'kırmızı': ['elma', 'çilek'],
'sarı': ['muz', 'ananas'],
'yeşil': ['üzüm', 'avokado']
};

function test(renk) {
return meyveler[renk] || [];
}

Alternatif olarak Map kullanarakta aynı sonuca ulaşabiliriz:

// renk bazlı meyveleri bulmak için Map kullanımı
const meyveler = new Map()
.set('kırmızı', ['elma', 'çilek'])
.set('sarı', ['muz', 'ananas'])
.set('yeşil', ['üzüm', 'avokado']);

function test(renk) {
return meyveler.get(renk) || [];
}

Map ES2015'te kullanıma giren bir obje tipi. Anahtar-Değer eşleşmesi tutmanıza izin verir.

Switch ifadesini kullanmak yasak mı? Kendinizi koşullamayın, limitlemeyin. Kişisel olarak mümkün olduğu kadar object literal kullanıyorum.

Syntaxı elden geçir #

Yukarıdaki örneği Array.filter kullanarak çok daha basit halde yazabiliriz.

const meyveler = [
{ isim: 'elma', renk: 'kırmızı' },
{ isim: 'çilek', renk: 'kırmızı' },
{ isim: 'muz', renk: 'sarı' },
{ isim: 'ananas', renk: 'sarı' },
{ isim: 'üzüm', renk: 'yeşil' },
{ isim: 'avakado', renk: 'yeşil' }
];

function test(renk) {
// meyveleri renklerine göre filtrelemek için Array.filter kullanımı
return meyveler.filter(f => f.renk == renk);
}

Neredeyse her zaman aynı sonuca ulaşmak için birden fazla yol vardır. Bu maddede 4 farklı yöntem ile aynı sonuca ulaştık.

5. Array.every & Array.some kullanımı #

Son önerim yeni JavaScript özellikleriyle (aslında bir kaç yıldan fazla oldu) daha az satırda nasıl yazarız bununla ilgili olacak. Aşağıdaki koda göz atın, tüm meyvelerin kırmızı renkte olduğunu kontrol etmek istiyoruz:

const meyveler = [
{ isim: 'elma', renk: 'kırmızı' },
{ isim: 'muz', renk: 'sarı' },
{ isim: 'üzüm', renk: 'yeşil' }
];

function test() {
let hepsiKirmizi = true;

// koşul, tüm meyveler kırmızı olmalı
for (let m of meyveler) {
if (!hepsiKirmizi) break;
hepsiKirmizi = (m.renk == 'kırmızı');
}

console.log(hepsiKirmizi); // false
}

Kod çok uzun! Array.every kullanarak satır sayısını azaltabiliriz:

const meyveler = [
{ isim: 'elma', renk: 'kırmızı' },
{ isim: 'muz', renk: 'sarı' },
{ isim: 'üzüm', renk: 'yeşil' }
];

function test() {
// kısa yollu koşul, tüm meyveler kırmızı olmalı
const hepsiKirmizi = meyveler.every(f => f.renk == 'kırmızı');

console.log(hepsiKirmizi); // false
}

Çok daha temiz değil mi? Benzer bir yöntem ile herhangi bir meyvenin kırmızı olup olmadığını da Array.some ile kontrol edebiliriz.

Özetle #

Daha okunabilir kodlar yazmamız gerektiğini düşünüyorum. Umarım bu makaleden yeni bir şey öğrenmişsinizdir.

🙏🙏🙏

Buraya kadar okuduğun için teşekkür ederim, bu makaleyi favori sosyal medya ağında paylaşman beni çok mutlu edecek 💖! Geri bildirim için, lütfen Twitter'da bana ulaşın.

Yayınlanma