12 Kasım 2022

Yapıcı, "new" operatörü

{ ... } yazımı bir objenin yaratılmasına yarar. Fakat bir objenin benzeri farklı objeler yaratmak istenebilir. Örneğin farklı kullanıcılar, farklı menü değerleri.

Bu yapıcı fonksiyon ve "new" operatörü ile yapılabilir.

Yapıcı fonksiyon

Yapıcı fonksiyonlar(Constructor) teknik olarak normal fonksiyonlardır. Tabi bazı farklılıkları vardır:

  1. Büyük harfle başlayarak adlandırılırlar.
  2. Sadece "new" operatörü kullanıldığında çalışırlar.

Örneğin:

function Kullanici(isim) {
  this.isim = isim;
  this.yoneticiMi = false;
}

let kullanici = new Kullanici("İhsan");

alert(kullanici.isim); // İhsan
alert(kullanici.yoneticiMi); // false

Fonksiyon new Kullanici(...) şeklinde çalıştığında, aşağıdaki adımlar izlenir:

  1. Yeni bir obje yaratılır ve this bu obje olur.
  2. Fonksiyon gövdesi çalışır. Genelde this modifiye edilir ve yeni özellikler eklenir.
  3. this değeri dönderilir.

Diğer bir deyişle, new Kullanici(...) şöyle yapar:

function Kullanici(isim) {
  // this = {};  (üstü kapalı)

  // bu objeye yeni özellikler ekle
  this.isim = isim;
  this.yoneticiMi = false;

  // return this;  (üstü kapalı)
}

Öyleyse `new Kullanici(“İhsan”) objesi aşağıdaki gibidir:

let kullanici = {
  isim: "Jack",
  yoneticiMi: false
};

Eğer başka bir kullanici oluşturmak istiyorsanız, yapmanız gereken new Kullanici("Macide"), new Kullanici("Muzaffer") gibi kullanmaktır. Doğrudan her defasında obje tanımlamaktan daha kısa ve anlaşılması kolaydır.

Yapıcı fonksiyonların amacı – tekrar kullanılabilecek objeleri yaratan kodun uygulanmasıdır.

Dikkat edecek olursanız, herhangi bir fonksiyon yapıcı fonksiyon olarabilir. Her fonksiyon new ile çalıştırılabilir, ve yukarda anlatılan algoritmaya göre çalışır. “Yapıcı fonksiyon isimleri büyük harfle başlamalıdır” aslında genel bir ittifaktır, bunu daha da açıklayıcı yapmak için bu fonksiyonlar new ile çağırılmalıdır.

new function() { … }

Eğer birçok satırdan oluşan kodda amacınız sadece karmaşık bir obje yapmak ise, bunları yapıcı fonksiyon içine aşağıdaki gibi almak mümkündür:

let kullanici = new function() {
  this.isim = "İhsan";
  this.yonetici = false;

  // diğer karmaşık yapılar
  // mantıklar veya yerel değişkenler
};

Yapıcı fonksiyon tekrar çağırılamaz çünkü hiçbir yere kayıt edilmemiştir, sadece yaratılır ve çağırılır. Böylece yapıcı metod ilerde tekrar kullanılmayacağına garanti verir.

Yapıcı modu testi: new.target

İleri düzey konular

Bu olay çok nadir kullanılır. Eğer her şeyi öğrenmek istemiyorsanız burayı geçebilirsiniz.

Fonksiyon içinde, bu fonksiyon new ile mi yoksa new olmadan mı çağırılmış bu new.target özelliği kullanılarak anlaşılabilir.

Normal çağrılarda bunun içerisi boştur fakat new ile çağrılırsa:

function Kullanici() {
  alert(new.target);
}

// new kullanılmadan:
User(); // new.target undefined döndürür.

// new kullanılarak:
new User(); // function Kullanici { ... } gibi ekrana fonksiyonu yazar

new ve normal sözdiziminin(syntax) aynı çalışmasını sağlar:

function Kullanici(isim) {
  if (!new.target) { // eğer çart yerine getirilmezse
    return new Kullanici(isim); // ...yeni birisi eklenir.
  }

  this.isim = isim;
}

let ihsan = Kullanici("John"); // çağrıyı new Kullanici(isim) fonksiyonuna yönlendirir.
alert(ihsan.isim); // İhsan

Bu yaklaşım bazı kütüphanelerde yazımı daha esnek yapabilmek amacıyla kullanılır. Her yerde kullanılması o kadar da iyi değildir. Çünkü new ne olup bittiği hakkında bilgi vermektedir. new ile yeni bir obje yaratıldığını anlayabiliyorsunuz ki bu da iyi bir şeydir.

Yapıcı metodun return sözcüğü

Genelde yapıcı metodların return sözcüğü yoktur. Amaçları gerekli olan bilgileri this içine yazmaktır ve bu da otomatik olarak sonuçtur.

Fakat return sözcüğü var ise kurallar basittir:

  • Eğer return obje ile çağırılırsa this yerine bu obje döndürülür.
  • Eğer return ilkel bir obje ile çağırılırsa görmezden gelinir.

Diğer bir deyişle, obje ile return kullanıldığında obje döner, diğer tüm hallerde this döner.

Örneğin aşağıda return edilen obje this yerine dönderilir.

function BuyukKullanici() {

  this.isim = "İhsan";

  return { isim: "Muhsin" };  // <-- obje dönderir
}

alert( new BuyukKullanici().isim );  // Muhsin, objeyi aldık ^^

Şimdi ise boş bir return cümlesi yazalım( eğer ilkel bir tipte kullanılsa bir şey değiştirmez)

function KucukKullanici() {

  this.isim = "İhsan";

  return; // çalışmayı bitirir ve `this`'i döndürür.

}

alert( new KucukKullanici().isim );  // İhsan

Genelde yapıcılar return sözcüğü kullanmazlar. Buarada amaç bütünlüğün sağlanması için geçerli olan özel bir davranıştır.

Parantezlerin yazılmaması

Bu arada new'den sonra eğer bir argüman yoksa parantez kullanmasanız da olur:

let kullanici = new Kullanici; // <-- parantez yok
// aynı şey.
let kullanici = new Kullanici();

Parantezleri yazmamak “iyi yazım stili” değildir. Fakat bu şekilde yazım da mümkündür.

Yapıcı içerisinde metod

Yapıcı fonksiyon kullanmak objeye mükemmel esneklik sağlar. Yapıcı fonksiyon parametreleri tanımlar ve objenin nasıl yapılacağını, ne konulması gerektiğini belirtir.

Tabiki this'e sadece özelliklerde değil metodlar içerisinde de ekleme yapılabilir.

Örneğin, aşağıdaki new User(isim) verilen isim ile yeni bir obje oluşturur. Bu obje selamVer metoduna sahiptir.

function Kullanici(isim) {
  this.isim = isim;

  this.selamVer = function() {
    alert( "Benim adım: " + this.isim );
  };
}

let ihsan = new Kullanici("ihsan");

ihsan.selamVer(); // Benim adım: İhsan

/*
ihsan = {
   name: "İhsan",
   selamVer: function() { ... }
}
*/

Özet

  • Yapıcı fonksiyonlar, veya kısaca yapıcılar, normal fonksiyonlardır. Fakat baş haflerinin büyük olmasıyla ilgili ortak bir kullanım vardır.
  • Bu fonksiyonlar sadece new kullanılarak çağırılmalıdır. Böyle çağrılar önce boş bir this yaratır ve buna değerler eklendikten sonra bu this'i geri gönderir.

Yapıcılar ile benzer objeler yapmak mümkündür.

JavaScript kendi içerisindeki objeler için yapıcı fonksiyon desteği verir. Örneğin: Tarihler için Date, setler için Set vs.

Objelere tekrar dönülecektir!

Bu bölümde basitçe yapıcılar nasıl yaratılır bunlar hakkında konuşuldu. Bir sonraki bölümde daha fazla veri tipi ve fonksiyonlar hakkında bilgi verilecektir.

"object-oriented-programming" adresindeki makale bulunamadı bölümde objelere geri dönülmiş ve derinlemesine incelenmiştir.

Görevler

önem: 2

new A() == new B() şeklinde A ve B fonksiyonları yaratmak mümkün müdür?

function A() { ... }
function B() { ... }

let a = new A;
let b = new B;

alert( a == b ); // true

Eğer mümkünse, bi işi yapan kodu yazınız. If it is, then provide an example of their code.

Evet mümkün.

Eğer bir fonksiyon obje döndürüyorsa this yerine o objeyi döndürebilir.

Öyleyse, iki fonksiyon da dışarıda yaratılmış aynı objeyi dönderirse bu durumda aynı olur:

let obj = {};

function A() { return obj; }
function B() { return obj; }

alert( new A() == new B() ); // true
önem: 5

Yapıcı HesapMakinesi fonksiyonunu yazınız ve aşağıdaki üç fonksiyonu buna uygulayınız:

  • oku() veri giriş ekranı gösterir ve iki değeri objenin özelliklerine kaydeder.
  • topla() kaydedilen değerlerin toplamını döner.
  • carp() kaydedilen değerlerin çarpımını döner.

Örneğin:

let hesapMakinesi = new HesapMakinesi();
hesapMakinesi.oku();

alert( "Toplam=" + hesapMakines.topla() );
alert( "Çarpım=" + hesaoMakinesi.carp() );

Demoyu çalıştır

Testler ile korunaklı olan aç.

function HesapMakinesi() {

  this.oku = function() {
    this.a = +prompt('a?', 0);
    this.b = +prompt('b?', 0);
  };

  this.topla = function() {
    return this.a + this.b;
  };

  this.carp = function() {
    return this.a * this.b;
  };
}

let hesapMakinesi = new HesapMakinesi();
hesapMakimesi.oku();

alert( "Toplam=" + hesapMakinesi.topla() );
alert( "Carpım=" + hesapMakinesi.carp() );

Çözümü testler korunaklı alanda olacak şekilde aç.

önem: 5

Toplayici(baslangicDegeri) yapıcı fonksiyonunu yazınız.

Yaratacağı obje:

  • deger icerisinde o anki değeri tutmalı, başlangıç değeri baslangicDegeri argümanı ile sağlanacaktır.
  • oku() metodu kullanıcıdan prompt ile bilgi almalı ve bunu deger'e eklemelidir.

Diğer bir deyişle deger özelliği tüm kullanıcıların girdiği değerlerin baslangicDegeri ile toplamıdır.

Aşağıda bir demosunu görmektesiniz:

let toplayici = new Toplayici(1); // toplayıcıya  1 ile başla.
toplayici.oku(); // kullanıcının girdiği değeri toplar.
toplayici.oku(); // kullanıcının girdiği değeri toplar.
alert(toplayici.deger); // toplamı gösterir.

Demoyu çalıştır

Testler ile korunaklı olan aç.

function Toplayici(baslangicDegeri) {
  this.deger = baslangicDegeri;

  this.oku = function() {
    this.deger += +prompt('Kaç eklemek istersiniz?', 0);
  };

}

let toplayici = new Toplayici(1);
toplayici.oku();
toplayici.oku();
alert(toplayici.deger);

Çözümü testler korunaklı alanda olacak şekilde aç.

Eğitim haritası

Yorumlar

yorum yapmadan önce lütfen okuyun...
  • Eğer geliştirme ile alakalı bir öneriniz var ise yorum yerine github konusu gönderiniz.
  • Eğer makalede bir yeri anlamadıysanız lütfen belirtiniz.
  • Koda birkaç satır eklemek için <code> kullanınız, birkaç satır eklemek için ise <pre> kullanın. Eğer 10 satırdan fazla kod ekleyecekseniz plnkr kullanabilirsiniz)