JavaScript'te default parametre, bir argüman hiç verilmediğinde ya da undefined verildiğinde kullanılacak değeri fonksiyon başlığında tanımlamanızı sağlar: function f(a, b = 1). Rest parametre (...args) kalan tüm argümanları gerçek bir diziye toplar. arguments nesnesi ise arrow olmayan her fonksiyonda bulunan, gelen tüm argümanları tutan dizi benzeri eski bir yapıdır; MDN modern kodda onun yerine rest parametrelerin tercih edilmesini önerir.

Bu yazıda üç yapıyı da çalıştırılmış örneklerle ele alıyoruz: default değerlerin ne zaman devreye girdiği, çağrı anında yeniden hesaplanması, kendi kapsamları, rest parametrenin kuralları ve arguments ile farkları. Destructuring ile parametre kullanımının ayrıntıları için destructuring ve spread yazısına bakabilirsiniz.

Default parametre: undefined yerine bir değer

Default parametre: undefined yerine bir değer

JavaScript'te verilmeyen bir parametrenin değeri undefined olur. Eskiden bunu fonksiyon gövdesinde kontrol ederdik. Default parametreyle varsayılan değer doğrudan başlıkta yazılır:

javascript
function toplamEski(birim, adet) {
  return birim * adet;
}
console.log(toplamEski(50)); // NaN

function toplam(birim, adet = 1) {
  return birim * adet;
}
console.log(toplam(50)); // 50
console.log(toplam(50, 3)); // 150
console.log(toplam(50, undefined)); // 50

Son satır önemlidir: Açıkça undefined vermek, argümanı hiç vermemekle aynı sonucu doğurur. Ancak bu kural yalnızca undefined için geçerlidir; null, 0, boş metin ya da false gibi falsy değerler varsayılanı tetiklemez:

javascript
function test(sayi = 1) {
  return `${typeof sayi}: ${sayi}`;
}
console.log(test()); // number: 1
console.log(test(undefined)); // number: 1
console.log(test(null)); // object: null
console.log(test("")); // string:
console.log(test(0)); // number: 0

Varsayılan değer her çağrıda yeniden hesaplanır

Default ifade fonksiyon tanımlanırken değil, her çağrıda değerlendirilir. MDN bunu Python ile karşılaştırarak vurgular: JavaScript'te varsayılan olarak verilen boş dizi her çağrıda yeni bir dizidir. Varsayılan ifade bir fonksiyon çağrısıysa o fonksiyon da her seferinde çalışır:

javascript
function ekle(deger, dizi = []) {
  dizi.push(deger);
  return dizi;
}
console.log(ekle(1)); // [ 1 ]
console.log(ekle(2)); // [ 2 ]

let sayac = 0;
function siradaki() {
  sayac++;
  return sayac;
}
function kayit(no = siradaki()) {
  return no;
}
console.log(kayit(), kayit(), kayit(99), kayit()); // 1 2 99 3

kayit(99) çağrısında argüman verildiği için siradaki() hiç çalışmaz; bu yüzden sonraki çağrı 3 döndürür.

Önceki parametreler, sonrakilerin varsayılanında kullanılabilir

Parametreler soldan sağa başlatılır. Bu sayede bir varsayılan değer, kendisinden önce gelen parametreleri kullanabilir. Buna karşılık default başlatıcılar fonksiyon gövdesinin üstündeki ayrı bir kapsamda çalışır; gövdede tanımlanan fonksiyon ve değişkenleri göremez:

javascript
function selamla(ad, hitap, mesaj = `${hitap} ${ad}`) {
  return mesaj;
}
console.log(selamla("Ece", "Merhaba")); // Merhaba Ece
console.log(selamla("Ece", "Merhaba", "İyi günler")); // İyi günler

function f(a = yardimci()) {
  function yardimci() {
    return 1;
  }
  return a;
}
try {
  f();
} catch (e) {
  console.log(e.name + ": " + e.message); // ReferenceError: yardimci is not defined
}

Kapsamların genel mantığı için scope yazısına bakabilirsiniz. MDN ayrıca default ifadede await ya da yield ile beklemenin mümkün olmadığını, parametrenin senkron olarak başlatılması gerektiğini belirtir.

Destructuring ile varsayılan değerler

Destructuring ile varsayılan değerler

Ayar nesnesi alan fonksiyonlarda default parametre ile destructuring birlikte çok kullanışlıdır. Nesnenin tamamına boş nesne (= {}) varsayılanı verirseniz fonksiyonu hiç argümansız da çağırabilirsiniz:

javascript
function baglan({ host = "localhost", port = 3000 } = {}) {
  return `${host}:${port}`;
}
console.log(baglan()); // localhost:3000
console.log(baglan({ port: 8080 })); // localhost:8080
console.log(baglan({ host: "api.ornek.com", port: 443 })); // api.ornek.com:443

Sondaki = {} olmasaydı baglan() çağrısı, undefined değerini parçalamaya çalışacağı için TypeError verirdi.

Rest parametre: kalan argümanları diziye toplamak

Son parametrenin başına üç nokta koyarsanız, adlandırılmış parametrelerden sonra gelen tüm argümanlar gerçek bir Array içinde toplanır. Hiç fazladan argüman yoksa rest parametre boş bir dizidir, asla undefined değildir:

javascript
function topla(...sayilar) {
  return sayilar.reduce((t, n) => t + n, 0);
}
console.log(topla()); // 0
console.log(topla(1, 2, 3)); // 6
console.log(topla(5, 10, 15, 20)); // 50

function carp(carpan, ...degerler) {
  return degerler.map((d) => d * carpan);
}
console.log(carp(2, 15, 25, 42)); // [ 30, 50, 84 ]

Rest parametrenin dört sözdizimi kuralı vardır: Bir fonksiyonda yalnızca bir tane olabilir, en sonda olmalıdır, ardından sondaki virgül (trailing comma) gelemez ve varsayılan değer alamaz. Node.js 24'te bu kuralları ihlal eden tanımlar şu hataları verir:

javascript
function a(...x, y) {}
// SyntaxError: Rest parameter must be last formal parameter

function b(...x = []) {}
// SyntaxError: Rest parameter may not have a default initializer

Rest parametre, çağrı tarafındaki spread sözdiziminin tersidir: Spread bir diziyi argümanlara açar, rest argümanları diziye toplar. Math.max(...sayilar) ile Math.max.apply(null, sayilar) aynı sonucu verir; apply ayrıntıları this ve call/apply/bind yazısında.

arguments nesnesi

arguments, arrow olmayan fonksiyonların içinde kendiliğinden bulunan yerel bir değişkendir. Sıfırdan başlayan indeksleri ve length özelliği vardır, yinelenebilir (iterable) bir nesnedir, ama dizi değildir; map ya da forEach gibi dizi metotlarını doğrudan kullanamazsınız. Kullanmak isterseniz önce Array.from(), spread ya da Array.prototype.slice.call() ile diziye çevirirsiniz:

javascript
function eski() {
  console.log(typeof arguments, Array.isArray(arguments), arguments.length); // object false 3
  const dizi = Array.from(arguments);
  return dizi.map((x) => x * 2);
}
console.log(eski(1, 2, 3)); // [ 2, 4, 6 ]

function yeni(...args) {
  console.log(Array.isArray(args), args.length); // true 3
  return args.map((x) => x * 2);
}
console.log(yeni(1, 2, 3)); // [ 2, 4, 6 ]

function ikisi(a, ...kalan) {
  return [arguments.length, kalan.length];
}
console.log(ikisi("x", "y", "z")); // [ 3, 2 ]

Son örnek önemli bir farkı gösterir: arguments tüm argümanları içerir, rest parametre ise yalnızca adlandırılmış parametrelerden sonra kalanları. Arrow function'larda arguments bulunmadığını da hatırlatalım; ayrıntılar fonksiyon türleri yazısında.

arguments ile parametrelerin eşitlenmesi

Strict olmayan ve yalnızca basit parametreler (default, rest ya da destructuring olmayan) içeren fonksiyonlarda arguments indeksleri parametrelerle eşitlenir: Birini değiştirirseniz diğeri de değişir. Default parametre eklediğinizde ya da strict mode kullandığınızda bu bağ kopar:

javascript
function basit(a) {
  arguments[0] = 99;
  return a;
}
console.log(basit(10)); // 99

function varsayilanli(a = 0) {
  arguments[0] = 99;
  return a;
}
console.log(varsayilanli(10)); // 10

function kati(a) {
  "use strict";
  arguments[0] = 99;
  return a;
}
console.log(kati(10)); // 10

Fonksiyonun length değeri

Bir fonksiyonun length özelliği beklediği parametre sayısını gösterir, ama ilk default parametre ve ondan sonraki parametreler ile rest parametre bu sayıya dahil edilmez:

javascript
function f1(a, b, c) {}
function f2(a, b = 1, c) {}
function f3(a, ...rest) {}
console.log(f1.length, f2.length, f3.length); // 3 1 1

rest parametre ve arguments karşılaştırması

rest parametre ve arguments karşılaştırması: Gerçek Array, Dizi metotları, İçerik, Arrow function
ÖzellikRest parametrearguments
TürGerçek ArrayDizi benzeri nesne
Dizi metotlarıDoğrudan kullanılırÖnce diziye çevrilmeli
İçerikYalnızca kalan argümanlarTüm argümanlar
Arrow functionKullanılabilirYok, dış fonksiyonunkine bakar
Parametrelerle eşitlenmeHiçbir zamanYalnızca strict olmayan, basit parametreli fonksiyonlarda
callee özelliğiYokVar (eskimiş, strict mode yasak)
Fonksiyon length değerine etkisiSayılmazİlgisiz

Sık yapılan hatalar

  • Varsayılan değerin null verildiğinde de devreye gireceğini sanmak; yalnızca undefined için çalışır.
  • Varsayılan parametreyi zorunlu parametrelerden önce yazıp sonraki parametreleri vermeden çağırmak: f(x = 1, y) tanımında f(2) çağrısı x değerini 2 yapar, y ise undefined kalır.
  • Rest parametreden sonra başka bir parametre yazmak ya da ona varsayılan değer vermek.
  • arguments üzerinde doğrudan map çağırmak.
  • Arrow function içinde arguments kullanmak.
  • Ayar nesnesini parçalayan parametreye = {} eklemeyi unutup fonksiyonu argümansız çağırmak.

Sık Sorulan Sorular

Default parametre ile || operatörü arasındaki fark nedir?

|| sol taraf falsy olduğunda (0, boş metin, false, null, undefined, NaN) sağ tarafı seçer. Default parametre ise yalnızca argüman verilmediğinde ya da undefined olduğunda devreye girer.

Rest parametre ile spread aynı şey mi?

Yazımları aynıdır (...), görevleri terstir. Fonksiyon tanımında kullanılan rest, argümanları diziye toplar; çağrıda ya da dizi literalinde kullanılan spread, bir diziyi öğelerine açar.

arguments kullanmak hâlâ doğru mu?

Çalışır ve eski kodlarda sıkça görürsünüz, ama MDN modern kodda rest parametreleri önerir. Rest parametre gerçek bir dizidir, arrow function'larda da kullanılabilir ve hangi argümanları topladığı açıkça görünür.

Varsayılan değer olarak başka bir parametre kullanılabilir mi?

Evet, ama yalnızca kendisinden önce (solda) tanımlanan parametreler kullanılabilir. Gövdede tanımlanan değişken ve fonksiyonlar varsayılan ifadede görünmez, kullanırsanız ReferenceError alırsınız.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: JavaScript öğrenme rehberi · Fonksiyon türleri · Destructuring ve spread · Optional chaining ve ?? · Scope ve kapsam · TypeScript ileri seviye