Menu

JavaScript Rest ve Spread: ... Operatörü Rehberi

JavaScript'te ... operatörünün nasıl çalıştığını konuşalım: rest parametreleriyle argümanları toplamak, spread ile dizi ve nesneleri açmak, hangisi ne zaman kullanılır?

Aynı Sözdizimi, İki Farklı Görev

Modern JavaScript kodunda üç noktayı (...) çok sık görürsün ve nerede kullanıldığına göre birbirinin tam tersi iki iş yapar. Aslında mantığı yakaladığında, ... operatörünün her kullanımı şu iki kategoriden birine düşer:

  • Rest: Alıcı tarafta ...isim şeklinde yazıldığında, birden fazla değeri tek bir dizi ya da nesnede toplar.
  • Spread: Veren tarafta ...değer şeklinde yazıldığında, bir diziyi ya da nesneyi tek tek parçalarına ayırır.

Zihin modelinin tamamı bu kadar. Sayfanın geri kalanı sadece her iki kullanıma dair örnekler ve pratikte sürekli başvuracağın kalıplardan oluşuyor.

Rest Parametreleri: Argümanları Toplamak

Fonksiyon tanımında kullanılan bir rest parametresi, gelen argümanları — kaç tane olursa olsun — gerçek bir dizi hâlinde toplar:

index.js
Output
Click Run to see the output here.

nums artık sıradan bir dizi. .map edebilir, .filter edebilir, .length'ine bakabilir, başka bir fonksiyona geçirebilirsin — dizilerle ne yapıyorsan hepsi geçerli.

Rest parametrelerini normal parametrelerle birlikte kullanabilirsin; tek şart, rest parametresinin en sonda yer alması:

index.js
Output
Click Run to see the output here.

label ilk argümanı yakalar; geri kalan her şey items içine düşer. Rest parametresini son sıranın dışında bir yere yazarsan syntax error alırsın.

Rest parametresi ve eski arguments nesnesi

Eski JavaScript kodlarında, normal fonksiyonların içinde arguments adında sihirli bir değişken kullanılır. Görünüşte diziye benzer ama aslında dizi değildir; bu yüzden dizi metotlarını doğrudan üzerinde çalıştıramazsın. Rest parametreleri bunun yerine çok daha temiz bir çözüm sunuyor:

index.js
Output
Click Run to see the output here.

Arrow fonksiyonlarının arguments objesi bile yoktur; dolayısıyla değişken sayıda argüman almanın tek yolu rest parametreleridir. Yeni yazdığın kodda ...args kullanmayı tercih et.

Fonksiyon Çağrılarında Spread Kullanımı

Spread tam tersini yapar: bir diziyi alır ve çağrı sırasında elemanlarını tek tek argümanlara açar.

index.js
Output
Click Run to see the output here.

Math.max tek tek sayıları parametre olarak alır, bir dizi değil. Spread operatörü gelmeden önce Math.max.apply(null, nums) yazmak zorundaydık. Artık bir ... yeterli, iş tamam.

Dikkat ederseniz, aynı ... operatörü fonksiyon tanımında rest, fonksiyon çağrısında ise spread olarak davranıyor — hangisi olduğunu bulunduğu konumdan anlıyoruz.

Dizi Literallerinde Spread Kullanımı

Bir dizi literaline spread yaparak diziyi kopyalayabilir veya birden fazla diziyi birleştirebilirsiniz:

index.js
Output
Click Run to see the output here.

[...a] ile orijinal diziye dokunmadan aynı elemanları içeren yepyeni bir dizi elde edersin. Sıralama veya başka değişiklikler yapmak istediğinde tam aradığın şey:

index.js
Output
Click Run to see the output here.

scores dizisine hiç dokunulmadı; çünkü .sort kopya üzerinde çalıştı. Küçük bir alışkanlık ama sürpriz yan etkileri olmayan kod yazmak istediğinde faydası büyük.

Nesne Literallerinde Spread Kullanımı

Spread operatörü düz nesnelerde de çalışır; özellikleri alıp yeni bir nesneye birleştirir:

index.js
Output
Click Run to see the output here.

Sonradan yazılan anahtar kazanır. updates.age, user.age değerini ezer; city de yanında geliverir. Sonucu belirleyen şey spread'lerin sırasıdır — varsayılanları ve geçersiz kılmaları üst üste bindirirken bunu aklınızda tutun:

index.js
Output
Click Run to see the output here.

Önce varsayılanlar, ardından kullanıcı tercihleri geliyor. fontSize değerini kullanıcı belirliyor, theme ise varsayılandan miras alınıyor.

Shallow Copy Tuzağı

Spread operatörü sadece bir seviye derinliğe kopyalar. İç içe geçmiş nesneler ve diziler, orijinal ile kopya arasında hâlâ paylaşılır:

index.js
Output
Click Run to see the output here.

Her iki dizide de yeni etiketin görünmesinin sebebi şu: copy.tags ile original.tags aslında aynı diziyi işaret ediyor. Spread, iç içe listeyi klonlamıyor; sadece referansı kopyalıyor.

Düz veriyi gerçekten derin kopyalamak istiyorsan structuredClone imdadına yetişir:

index.js
Output
Click Run to see the output here.

Artık iki dizi birbirinden tamamen bağımsız. structuredClone modern tarayıcılarda ve Node'da hazır olarak geliyor, iç içe yapılarla da sorunsuz başa çıkıyor; yani shallow copy'nin yetmediği her durumda doğru tercih bu.

Destructuring İçinde Rest Kullanımı

Rest, destructuring ile de gayet güzel çalışır; geriye kalan eleman ya da özellikleri tek seferde toplar:

index.js
Output
Click Run to see the output here.

Bir nesneden birkaç alanı çekip geri kalanını tek bir nesnede toplamak, prop'ları ileri aktarırken, hassas alanları ayıklarken ya da verinin yamalı bir sürümünü oluştururken sıkça karşılaştığımız bir kalıptır:

index.js
Output
Click Run to see the output here.

password çekilip kenara atılıyor (yok sayılıyor); geri kalan her şey safe içinde kalıyor. Ne mutasyon var, ne de elle kopyalama.

Kısa Bir Özet

  • Parametre listesinde veya destructuring kalıbında kullanılan ...name rest'tir: toplar.
  • Fonksiyon çağrısında, dizi literal'ında veya nesne literal'ında kullanılan ...value ise spread'dir: yayar.
  • Spread ile yapılan kopyalar shallow (yüzeysel) kopyadır. İç içe yapılar hâlâ paylaşılır. Derin kopya için structuredClone kullan.
  • Rest parametreleri gerçek birer array'dir — arguments yerine bunları tercih et.
  • Nesne literal'larında sonra gelen spread öncekini ezer; "varsayılanlar + override" desenini bu şekilde kurarsın.

Sırada: Closure'lar

JavaScript'te fonksiyonlar sadece girdi alıp çıktı üretmez — tanımlandıkları scope'u da hatırlar. İşte bu hafızaya closure denir. Callback'lerin, factory fonksiyonlarının ve bir sonraki sayfada karşılaşacağın pek çok desenin arkasındaki mekanizma da budur.

Sıkça Sorulan Sorular

JavaScript'te rest ve spread arasındaki fark nedir?

İkisi de aynı ... sözdizimini kullanır ama işleri birbirinin tam tersidir. Rest, birden fazla değeri toplayıp tek bir diziye koyar; yani fonksiyon parametre listelerinde ve destructuring içinde karşınıza çıkar. Spread ise bir iterable'ı ya da nesneyi parçalarına açar; fonksiyon çağrılarında, dizi literal'lerinde ve nesne literal'lerinde görünür. Kısacası: ... alıcı taraftaysa rest'tir, veren taraftaysa spread'tir.

Rest parametreleri fonksiyon içinde nasıl çalışır?

function sum(...nums) şeklinde yazılan bir rest parametresi, fonksiyona gönderilen tüm argümanları toplayıp nums adında gerçek bir diziye koyar. Parametre listesinin sonunda olmak zorundadır. Eski arguments nesnesinin aksine rest parametresi tam anlamıyla bir dizidir, dolayısıyla .map, .filter ve .reduce gibi metotlar doğrudan üzerinde çalışır.

Spread operatörü deep copy yapar mı?

Hayır. Spread yalnızca tek seviyeli kopyalama yapar, yani shallow copy alırsınız. { ...user } ifadesi üst seviye anahtarları yeni bir nesneye taşır ama içerideki iç içe nesneler ve diziler hâlâ aynı referansı paylaşır. Gerçek bir deep copy için structuredClone(value) kullanabilirsiniz; düz veri için JSON üzerinden serileştirme de iş görür.

Coddy ile kodlamayı öğren

BAŞLA