Yazılım.
CevapSitesi.com Beta!
Çözüm Noktası
Facebook, Twitter, Google+ veya e-posta ile paylaşın.
| Sorular | Makaleler | Üyeler | Etiketler  | İletişim
Soru sormak ya da cevap vermek için;
giriş yapın veya üye olun.

Sosyal medya hesaplarınızla da giriş yapabilirsiniz.
0

JavaScript İle Nesneye Yönelik Programlama - OOP JavaScript

JavaScript nesneye yönelik / nesne yönelimli (Object Oriented) bir programlama dilidir. Ancak daha önce C# ve Java gibi diller kullandıysanız size biraz değişik gelebilir.

Nesneye yönelik JavaScript programlamada bu dillerden en önemli farklılık JavaScript'in prototip (prototype / ön örnek / ilk örnek) yöntemini kullanmasıdır. Buna classless (sınıfsız) veya prototype-oriented (prototip yönelimli) veya instance-based (örnek tabanlı) programlama da denir.

Prototip yönteminde sınıflar yoktur, sadece nesneler (sınıfların canlı örnekleri) vardır. Bir sınıftan nesne oluşturmak yerine daha önceden oluşturulmuş bir nesnenin (örneğin) prototipi veya örneğin kendisi prototip olarak kullanılıp yeni bir nesne oluşturulur. Ancak biraz sonra göreceğiniz gibi fonksiyonları birer sınıf tanımlaması varsayarak sınıf gibi kullanabilirsiniz.

JavaScript programlamada nesne tanımlamanın birkaç yolu vardır.

Object Literal (Nesne Asıl Verisi) Yöntemiyle Nesne Oluşturma ve Nesne Üyeleri (Özellikler ve Yöntemler)

Birincisi object literal (nesne asıl verisi) denilen yöntemdir. Bu yöntemde iki süslü parantez arasında nesnenizi tanımlarsınız ve bir ifade (expression) olduğundan sonuna bir ; koyun (şart değil).

Örnek:
var deneme = {};
Örnekteki boş bir nesnedir. Eğer bu nesneye özellik veya yöntem (metot / fonksiyon) tanımlamak isterseniz bunu özellik veya yöntem adından sonra iki nokta üstüste ve özellikler / yöntemler arasına virgül koyarak alttaki gibi yapabilirsiniz.

var kisi = {adi: "Ali", yasi: 25};
Bir nesneye yöntem eklemek isterseniz yöntem adından sonra yöntemi komple bir fonksiyon ifadesi (Function Expression) olarak yazın.

var kisi = {adi: "Ali", selamla: function() { console.log("Merhaba."); }};
(Örneklerde kullanılan console.log ile yapılan çıktıları görmek için tarayıcınızda F12 tuşuna basın. Altta, sağda veya ayrıca açılan penceredeki console / konsol sekmesini tıklayın.)

Bunu genellikle okuma kolaylığı olsun diye şuna benzer bir şekilde yazarız.
var kisi = {
    adi: "Ali",
    selamla: function () {
        console.log("Merhaba.");
    }
};
Veya var olan bir fonksiyonun referansını bildirmek için fonksiyon adı da yazabilirsiniz.
function selamYaz() {
    console.log("Merhaba.");
}

var kisi = {
    adi: "Ali",
    selamla: selamYaz    // selamYaz fonksiyon adının yanında () olmadığına dikkat edin.
};

console.log(kisi.adi);   // adi özelliğinin değerini konsola yaz (Ali yazar).
kisi.selamla();          // selamla yöntemini çalıştır (Merhaba yazar).
Bir nesneye sonradan özellik eklemek isterseniz, nesne tanımının içinde olmadığı halde doğrudan özellik adı yazarak atama yapabilir ve böylece özelliği oluşturabilirsiniz. Tabi aynı şey yöntemler için de geçerlidir.
var kisi = {
    adi: "Ali",
    selamla: function () {
        console.log("Merhaba.");
    }
};

kisi.soyadi = "Ünlü";      // soyadi isimli özelliği ekle ve Ünlü değerini ata.

// Nesneye vedalas isimli bir yöntem ekle.
kisi.vedalas = function() {
    console.log("Hoşçakal.");
};

console.log(kisi.soyadi);  // Ünlü yazar.
kisi.vedalas();            // Hoşçakal yazar.
Bir özellik veya yöntemi silmek isterseniz delete operatörünü kullanın.
var kisi = {
    adi: "Ali",
    selamla: function () {
        console.log("Merhaba.");
    }
};

console.log(kisi.adi);    // Ali yazar.
delete kisi.adi;          // adi özelliğini sil.
console.log(kisi.adi);    // undefined yazar. adi özelliği artık yoktur.
JavaScript nesneleri PHP'deki ilişkisel diziler (associative arrays) gibi çalışırlar. Bu sayede özelliklere ulaşmak için nokta gösteriminden (kisi.adi şeklinde yazmak / dot notation) başka parantez gösterimini (bracket notation) da kullanabiliriz. Bu gösterimde özellik adı nesne adının yanına bir noktadan sonra değil, parantez içinde string veya number olarak yazılır. Nokta gösteriminde olduğu gibi bu yöntemle de yeni özellik ve metotlar ekleyebilir ve mevcut olanlara ulaşabilirsiniz.
var kisi = {
    adi: "Ali",
    selamla: function () {
        console.log("Merhaba.");
    }
};

kisi.adi = "Ahmet";         // Nokta gösterimiyle
console.log(kisi.adi);      // Ahmet yazar.

kisi["adi"] = "Mehmet";     // Parantez gösterimiyle
console.log(kisi.adi);      // Mehmet yazar.

// veya

console.log(kisi["adi"]);   // Parantez gösterimiyle. Mehmet yazar.
Özellikler sayı olarak da isim alabilirler. Bu durumda bu özelliklere parantez gösterimi ile indeksleyici gibi ulaşabiliriz. Bu kullanım, özelliklere bir for döngüsü ile sırayla erişmeniz gerektiğinde faydalı olabilir.
var kisiler = {
    0: "Ali",
    1: "Veli",
    2: "Selami"
};

console.log(kisiler[1]);    // Veli yazar.

kisiler[3] = "Hale";        // Yeni bir özellik oluştur ve "Hale" değerini ata.

console.log(kisiler[3])     // Hale yazar.
Özelliklere döngü ile erişmekten söz açılmışken, bir nesnenin özelliklerine bir döngü içinde ulaşmanın bir yolu for ... in kullanmaktır. for ... in döngüsü foreach döngülerine benzer ve bir nesnenin özellik ve yöntemelerini teker teker gezmek için kullanılabilir.
var kisi = {
    adi: "Belirtilmemiş",
    selamla: function () {
        console.log("Merhaba. Ben " + this.adi + ".");
    }
};

for (var ozellikVeyaYontem in kisi)
    console.log(ozellikVeyaYontem);
Bu tür bir gezinti yaptığınızda türetilmiş nesnelerde dikkatli olun. Eğer nesnenin kendine ait olan özelliklerini bilmek isterseniz hasOwnProperty yöntemini kullanın.
var kisi = { };                                // Boş bir nesne oluştur
kisi.adi = "Ali";                              // Nesne için bir özellik oluştur ve değer ata.
console.log(kisi.hasOwnProperty("adi"));       // true yazar.
console.log(kisi.hasOwnProperty("soyadi"));    // false yazar. Nesnenin soyadi adlı bir özelliği yoktur.
console.log(kisi.hasOwnProperty("toString"));  // false yazar. toString, kisi nesnesinin değil, türetildiği nesne olan Object'in yöntemidir.
Özellikleri gezmenin başka yolları da vardır. Object.keys yöntemi, nesnenin özellik ve metodlarının bir listesini dizi olarak döndürür. Bu diziden yararlanarak özellik ve yöntemlerin isimlerini elde edebiliriz / gezebiliriz.

var kisi = {
    adi: "Belirtilmemiş",
    selamla: function () {
        console.log("Merhaba. Ben " + this.adi + ".");
    }
};

var ozelliklerVeYontemler = Object.keys(kisi);

// Bir for döngüsü ile özellik ve yöntem dizisinin elemanlarını gez.

for (var i = 0; i < ozelliklerVeYontemler.length; i++)
    console.log(ozelliklerVeYontemler[i]);

// Bir for ... of döngüsü ile özellik ve yöntem dizisinin elemanlarını gez.

for (var ozellikVeyaYontem of ozelliklerVeYontemler)
    console.log(ozellikVeyaYontem);

// Özellik ve yöntemlerin değerlerini almak isterseniz, özelliği parantez gösterimi ile kullanın.

for (var ozellikVeyaYontem of ozelliklerVeYontemler)
    console.log(kisi[ozellikVeyaYontem]);
Özellik adları evrensel karakterler (Unicode) ve tırnak içinde yazılmak şartıyla boşluk içerebilirler. Ancak boşluk varsa bu özellikleri sadece parantez gösterimiyle kullanabilirsiniz.
var kisiler = {
    "مدير": "Ali",
    "Müdür Yardımcısı": "Veli"
};

console.log(kisiler["مدير"]);              // Ali yazar.
console.log(kisiler.مدير);                 // Ali yazar.
console.log(kisiler["Müdür Yardımcısı"]);  // Veli yazar.
Bir nesne için özellik oluşturmanın başka bir yolu, Object nesnesinin defineProperty yöntemini kullanmaktır. Bu yöntemde parametre olarak nesnenin adı, özelliğin adı ve özelliği tanımlayan bir nesne bildiririz.
var kisi = {};

Object.defineProperty(kisi, "adi", {value: "Belirtilmemiş"});

console.log(kisi.adi);    // Belirtilmemiş yazar.
defineProperty yönteminin birinci parametresi olan nesne adı, kisi isimli nesnemiz olarak bildirildi. İkinci parametre olan özellik adı "adi" şeklinde çift tırnak içinde bildirildi (sayı ise doğrudan yazabilirsiniz). Üçüncü parametre ise özelliği tanımlayan (özelliğin özelliklerini bildiren) bir nesnedir. Bu nesnenin value (değer) özelliği, tanımlanan özelliğin değerini bildirir. Bu örnekle şunun aynısını yapmış olduk.
var kisi = {
    adi: "Belirtilmemiş"
};

console.log(kisi.adi);   // Belirtilmemiş yazar.
defineProperty yönteminde kullanılan özelliğin tanımlayıcı nesnesinde value özelliğinden başka şunlar yer alabilir.

enumerable (Sayılabilir):  Mantıksal bir değer alır. for .. in gibi bir döngü içinde nesnenin özelliklerine sıradan erişirken veya Object.keys yöntemi ile nesnenin özelliklerini isterken bu özelliğin kullanılabilir olup olmadığını / listelenip listelenmeyeceğini belirtir. Varsayılan değeri false.

writable (Yazılabilir): Özelliğin değişitirilip değiştirilemeyeceğini belirten mantıksal bir değer alır. Varsayılan değeri false.

configurable (Özellik tanımları değiştirelibir): Mantıksal bir değer alır. Özelliğin enumerable ve configurable (writeable hariç) davranışının değiştirilip değiştirilemeyeceğini belirler. delete operatörüyle bir özelliğin silinebilmesi için configurable olması gereklidir. Varsayılan değeri false.

get: Özellik değeri istendiğinde kendiliğinden çalıştırılacak bir fonksiyon tanımlanabilir. Varsayılan değeri undefined.

set: Özellik değeri değiştirilmek istendiğinde (özelliğe atama yapıldığında) kendiliğinden çalıştırılacak bir fonksiyon tanımlanabilir. Varsayılan değeri undefined.

value özelliğinin varsayılan değeri de undefined'dır.

defineProperty ile varsayılan değeri false olan tanımlayıcılar, doğrudan nokta veya parantez gösterimi ile özellik oluşturulduğunda true değerini alırlar. Yani doğrudan adını yazarak oluşturduğunuz özellikler enumerable, configurable ve writable olurlar.

defineProperty ile aynı özellik değişiklik yapmak amacıyla tekrar tanımlanabilir.

defineProperty ile komple örnek:

var kisi = {
    adi: "Ali",
    soyadi: "Ünlü"
};

Object.defineProperty(kisi,
                      "tamAdi",
                      {
                          // value: "",          // get kullanıldığından yazılmıyor. Yazılırsa hata verir.
                          configurable: true,
                          writeable: true,
                          enumerable: true,
                          get: function () {
                              return this.adi + " " + this.soyadi;
                          },
                          set: function (deger) {
                              var ind = deger.lastIndexOf(" ");
                              if (ind === -1)
                                  throw "Ad ve soyad aralarında bir boşluk olacak şekilde verilmeli.";
                              this.soyadi = deger.substring(ind + 1);
                              this.adi = deger.substring(0, ind);
                          }
                      }
                     );

kisi.tamAdi = "Kazım Ünlüol";              // Değer değiştirlmek istendiğinden, set fonksiyonu çalışır. deger parametresinin değeri "Kazım Ünlüol" olur.

console.log(kisi.adi);                     // Kazım yazar.
console.log(kisi.soyadi);                  // Ünlüol yazar.
console.log(kisi.tamAdi);                  // get fonksiyonu çalışır. adi ve soyadi özelliklerinin değerleri, aralarına bir boşluk eklenerek gönderilir.

kisi.tamAdi = "MehmetEmre";                // set fonksiyonu çalışır fakat boşluk olmadığından throw çalıştırılır ve hata verir.

Yapılandırıcı / Kurucu (Constructor) Fonksiyon Kullanarak Nesne Oluşturma

Nesne oluşturmanın ikinci yolu fonksiyon yapılandırıcı / kurucu (constructor) kullanmaktır. Bu yöntemde bir fonksiyon tanımlarsınız ve örnek oluşturmak için new operatörü ile fonksiyon adını belirtirsiniz. İşte bu yöntemde fonksiyonlar bir sınıf tanımlaması olarak kabul edilebilir.

Örnek:

// Sınıf olarak kullanılabilecek fonksiyon tanımı.
function Kisi() {}

// Bunu şu şekilde de yazabilirsiniz. Bu bir ifade (expression) olduğundan sonuna ; koyun.
// var Kisi = function() { };

// Sınıfın bir örneğini (nesne) oluşturma:
var ali = new Kisi;             // Yeni bir Kisi nesnesi oluştur.

// Üsttekini var ali = new Kisi(); şeklinde de yazabilirsiniz.
Ancak bu yöntemde özellik veya yöntem tanımlarken fonksiyon içinde, oluşturulan örneği ifade eden this kelimesini kullanmalısınız.

Üstteki object literal olarak tanımlanan nesnenin özellik ve yöntemlerini kullanan örnek:
function Kisi() {
    this.adi = "Ali";
    this.selamla = function() {
        console.log("Merhaba");
    };
}

var sen = new Kisi();      // sen isimli yeni bir Kisi nesnesi oluştur.
var ben = new Kisi();      // ben isimli yeni bir Kisi nesnesi oluştur.

console.log(sen.adi);      // sen isimli nesnenin adi özelliğinin değerini yaz (Ali yazar).
console.log(ben.adi);      // ben isimli nesnenin adi özelliğinin değerini yaz (Ali yazar).
sen.selamla();             // sen isimli nesnenin selamla yöntemini çalıştır (Merhaba yazar).
ben.selamla();             // ben isimli nesnenin selamla yöntemini çalıştır (Merhaba yazar).
Üstte de belirttiğimiz gibi this, oluşturulan örneği ifade eder. Yani tüm new ile oluşturulan Kisi türündeki nesnelerin adi özelliklerinin değeri "Ali" olacaktır ve tüm örnekler (sen ve ben) konsola "Merhaba" yazan selamla isimli bir yönteme sahip olacaktır. Yani bütün nesneler aynı olur.

Eğer nesnelerin özellik değerlerinin birbirinden farklı olmasını isterseniz onları yapılandırırken kullanılan fonksiyona parametreler ekleyin ve bu parametreleri özellik değerlerine atayın.

Bu yolla, daha işe yarar bir örnek şöyle tanımlanabilir:

function Kisi(adi) {

    // Örneğin adi özelliğine (this.adi) parametre olarak gelen adi değerini ata.
    this.adi = adi;

    this.selamla = function() {
        console.log("Merhaba, ben " + this.adi + ".");
    };

}

var ben = new Kisi("Ali");       // Yeni bir Kisi nesnesi oluştur.
var sen = new Kisi("Veli");      // Yeni bir Kisi nesnesi oluştur.
var o = new Kisi("Selami");      // Yeni bir Kisi nesnesi oluştur.

console.log(ben.adi);      // Ali yazar.
console.log(sen.adi);      // Veli yazar.
console.log(o.adi);        // Selami yazar.

ben.selamla();             // Merhaba, ben Ali. yazar.
sen.selamla();             // Merhaba, ben Veli. yazar.
o.selamla();               // Merhaba, ben Selami. yazar.
Bu nesneyi object literal olarak şöyle tanımlayabiliriz:
var kisi = {
    adi: "Ali",
    selamla: function() {
        console.log("Merhaba, ben " + this.adi + ".");
    }
};

console.log(kisi.adi);   // Ali yazar.
kisi.selamla();          // Merhaba, ben Ali. yazar.
veya
function selamYaz() {
    console.log("Merhaba, ben " + this.adi + ".");
}

var kisi = {
    adi: "Ali",
    selamla: selamYaz
};

console.log(kisi.adi);   // Ali yazar.
kisi.selamla();          // Merhaba, ben Ali. yazar.
Object literal kullanımında görebileceğiniz gibi, sadece tek bir örnek var olmaktadır. new operatörü ile başka bir örnek oluşturamazsınız. new operatörü sadece fonsiyon yapılandırıcılarla kullanılabilir. new kisi() seklinde bir deneme yaparsanız, kisi'nin yapılandırıcı olmadığını belirten bir hata alırsınız.

kisi, bir nesnedir ve aynı zamanda bir prototiptir. Yani örnek bir nesnedir ve bunu başka nesneler oluşturmak için kullanabiliriz.

Başlangıçta da belirttiğimiz gibi JavaScript nesne oluşturmak için prototip yöntemini kullanılır. Elimizde bir prototip varsa (object literal olarak tanımlanan nesnemiz bir prototiptir) ve bunun bir kopyasını oluşturmak isterseniz Object.create yöntemini kullanın.

Object.create Yöntemi İle Nesne Oluşturma

Object.create yöntemi, JavaScript ile nesne oluşturmanın üçüncü yoludur. Object.create yönteminde parametre olarak bir prototip bildirirsiniz ve bir nesne elde edersiniz (nesne döner). İşte bu yöntem, başlangıçta belirttiğim örneğin kendisini prototip olarak kullanarak nesne oluşturma yöntemidir.

Örnek:
var kisi = {
    adi: "Ali",
    selamla: function() {
        console.log("Merhaba, ben " + this.adi + ".");
    }
};

// kisi nesnesini prototip olarak kullanıp bir nesne oluştur ve ben değişkenine ata.

var ben = Object.create(kisi);
var sen = Object.create(kisi);

ben.selamla();                // Merhaba, ben Ali. yazar.
sen.selamla();                // Merhaba, ben Ali. yazar.
Tabi hemen dikkatimizi çekecek. Tüm örneklerin adi özelliklerinin değeri her zaman Ali oluyor. Bundan şunu anlamalıyız. Object.create ile prototip bildirerek nesne türetirsek aynısından yeni bir object literal olarak tanımlanmış nesnemiz olur.

Object.create yönteminin bir başka kullanımında, ikinci bir parametre ile defineProperty bölümünde açıkladığımız özellik ekleme yöntemine benzer şekilde, özellikleri ayrı ayrı tanımlayan bir nesne kullanabiliriz.

Örnek:

var kisi = Object.create(
                         {},
                         { adi:
                                {
                                  value: "Ali",
                                  writeable:true,
                                  enumerable:true,
                                  configurable: true
                                },
                           soyadi:
                                {
                                  value: "Ünlü",
                                  writeable:true,
                                  enumerable:true,
                                  configurable: true
                                }
                         }
                        );
Bu örnekte şunun aynısını yapmış olduk:

var kisi = {
    adi: "Ali",
    soyadi: "Ünlü"
};

Örnekte, Object.create yönteminin birinci parametresi olan prototip kısmında boş bir nesne bildirdik. Peki burada önceden tanımlanmış bir nesne bildirirseniz ne olur?

Bu durumda prototip nesnenin örneğini almış ve yeni veya yeniden tanımlanan özelliklerle genişletmiş olursunuz.

var kisi = {
    unvan: "",
    adi: "Ali",
    soyadi: "Ünlü"
};

var isci = Object.create(kisi, {
    unvan: { value: "İşçi" },           // unvan özelliğini yeniden tanımla (override).
    bolum: { value: "Üretim" }          // bolum isimli bir özellik ekle, değeri "Üretim" olsun.
});

console.log(isci.unvan);      // İşçi yazar
console.log(isci.adi);        // Ali yazar
console.log(isci.soyadi);     // Ünlü yazar.
console.log(isci.bolum);      // Üretim yazar.

Tabi bu örnekte yeni tanımlanan ve değiştirilen özelliklerin writeable değeri varsayılan olarak false olduğundan artık değiştirilemez. Değiştirmek isterseniz writable ve configurable özelliklerini de ekleyin.

Object Nesnesinin Örneği İle Nesne Oluşturma / new Object()

Bir nesne oluşturmanın dördüncü yolu, Object nesnesinin bir örneğini oluşturmaktır.
var o = new Object();
Bu durumda başlangıçta belirttiğimiz boş object literal şeklinde tanıtılan şu nesnenin aynısını oluşturmuş olursunuz.

var o = {};
Bunların her ikisi de Object'den türetildiğinden Object nesnesinin sonraki makalelerde açıklamayı düşündüğüm constructor, isPrototypeOf, propertyIsEnumerable, toLocaleString, valueOf, toString ve hasOwnProperty yöntemlerine  sahip olacaklardır.

Bu şekilde oluşturulan nesnelere, object literal nesnelerinde olduğu gibi sonradan özellik ve yöntemler ekleyebilirsiniz.

var kisi = new Object();
kisi.adi = "Ali";
kisi.selamla = function() {
    console.log("Merhaba. Ben " + this.adi + ".");
};

kisi.selamla();        // Merhaba. Ben Ali. yazar.

JavaScript Sınıf Bildirimleri (Class Declarations) ile Sınıf Tanımlama

Sınıf bildirimi şeklinde sınıf tanımlama ES6 ile eklenen bir özelliktir. Bu yöntemde diğer bazı programlama dillerinde olduğu gibi class bildirimi ile sınıf tanımlaması yaparsınız. Ancak sınıf bildirimi yöntemi ile sınıf tanımlama yapılıyor olsa da JavaScript hâlâ prototip yöntemini kullanmaktadır. Sınıf bildirimi genişçe bir konu olduğundan bunu JavaScript Sınıf Bildirimleri (Class Declarations) ile Sınıf Tanımlama makalemizde açıkladık.

Nesnelerin prototype Özelliği:

Bir fonksiyon yapılandırıcı kullanarak oluşturduğunuz nesnelerde prototype isimli bir özellik bulunur. Bu özellik bir nesnedir ve bu kullanılarak nesnenin prototip bilgilerine ulaşılabilir (Tabi prototype, bir nesne olduğundan Object nesnesinin yöntemlerini de kullanabilirsiniz.).

function Kisi(adi) {
    this.adi = adi;
    this.selamla = function () {
        console.log("Merhaba. Ben " + this.adi + ".");
    };
}

console.log(Kisi.prototype.constructor);  // Yapılandırıcı fonksiyonu ver.
Çıktısı (Tarayıcıya göre değişebilir):

function Kisi(adi) {
            this.adi = adi;
            this.selamla = function () {
                console.log("Merhaba. Ben " + this.adi + ".");
            };
        }

Örnekte sadece prototype özelliğinin constructor (yapılandırıcı / kurucu) özelliğini kullanarak yapılandırıcı yöntemin kendisini elde ettik.

prototype özelliğini farklı işlemler için kullanabilirsiniz. Şimdi bunlara bakalım.

prototype özelliğini kullanarak sınıfın tüm örnekleri için geçerli olacak özellik ve yöntemler ekleyebilirsiniz.

function Kisi(adi) {
    this.adi = adi;
    this.selamla = function () {
        console.log("Merhaba. Ben " + this.adi + ".");
    };
}

var ben = new Kisi("Hale");
var sen = new Kisi("Lale");

// Kisi sınıfına vedalas isimli bir yöntem ekle.
// Bu yöntem tüm sınıf örnekleri için geçerli olacaktır.
Kisi.prototype.vedalas = function () {
    console.log(this.adi + ": Hoşçakal.");
};

// ben isimli nesneye soyadi isimli bir özellik ekle ve bir değer ata.
// Bu sadece ben nesnesi için geçerli olacaktır.
ben.soyadi = "Ünlü";

ben.vedalas();   // Hale: Hoşçakal. yazar.
sen.vedalas();   // Lale: Hoşçakal. yazar.

console.log(ben.soyadi); // Ünlü yazar.
console.log(sen.soyadi); // undefined yazar. soyadi özelliği sadece ben isimli nesneye atanmıştır.
Örnekte görüldüğü gibi soyadi özelliği ben isimli nesneye atanmıştır. Bu atamadan sonra sadece ben isimli nesne soyadi isimli bir özelliğe sahip olacaktır. Ancak Kisi.prototype özelliği kullanılarak yapılan yöntem tanımlamasında bu yöntem tüm örneklere atanmıştır (tüm örneklerin vedalas isimli bir yöntemi olmuştur).

Burada önemli iki konuyu vurgulayayım. Birincisi, prototype nesnesinin (özelliğinin) ve Object nesnesinin yöntemlerini başka bir çok işlem tarafından kullanılabileceğinden değiştirmeyin. Sadece kendi oluşturduğunuz özellikler ile çalışın. İkincisi ise, eğer nesnenin çok fazla örneği var ve performans konusunda kaygılarınız varsa prototype özelliğini değiştirmemeyi düşünün.

Daha önce Object.create ile object literal şeklinde tanımlanan bir nesnenin örneğini oluşturmuştuk. Oluştururken, object literal şeklinde tanımlanan nesnelerin aynı zamanda bir prototip olduğunu da belirtmiştik. prototype özelliği kullanılarak Object.create yöntemiyle bir nesne oluşturulabilir. Burada nesnenin kendisi değil, yapılandırıcı fonksiyonun prototype özelliği kullanılacaktır.

function Kisi(adi) {
    this.adi = adi;
    this.soyadi = "Belirtilmemiş";
    this.selamla = function () {
        console.log("Merhaba. Ben " + this.adi + ".");
    };
}

// Kisi sınıfının prototipini kullanarak bir nesne oluştur.
var ben = Object.create(Kisi.prototype);

console.log(ben.adi);     // undefined yazar.
console.log(ben.soyadi);  // Belirtilmemiş yazar.
Nesne yapılandırıcı fonksiyon çağırılmadan oluşturulduğundan console.log(ben.adi) satiri undefined yazar. Yani adi özelliği henüz tanımlanmamıştır.

Eğer bu şekilde oluşturulan bir nesnede yapılandırıcı fonksiyonu çalıştırmak / yapılandırmak isterseniz, üstte belirttiğimiz Object'den devralınan constructor (prototype.constructor değil) yöntemini varsa parametreleri ile beraber çağırın. Yeni oluşturulan nesnenin bir prototype özelliği olmayacaktır ancak bir yapılandırıcı fonsiyona sahip olacaktır.

function Kisi(adi) {
    this.adi = adi;
    this.selamla = function () {
        console.log("Merhaba. Ben " + this.adi + ".");
    };
}

// Kisi sınıfının prototipini (prototype özelliğini) kullanarak bir nesne oluştur.
var ben = Object.create(Kisi.prototype);

ben.constructor("Lale");

console.log(ben.adi);   // Lale yazar.
ben.selamla();          // Merhaba. Ben Lale. yazar.
Üstteki Object.create ile nesne oluşturmayı açıkladığımız bölümdeki nesne oluşturma örneğini prototype özelliğini kullanarak şöyle de yazabiliriz.

var kisi = {
    adi: "Belirtilmemiş",
};
function KisiOlustur() { }

KisiOlustur.prototype = kisi;

var sekreter = new KisiOlustur();

console.log(sekreter.adi);   // Belirtilmemiş yazar.

__proto__ Özelliği

prototype özelliğinden bahsetmişken Mozilla'nın __proto__ özelliğinden de bir parça bahsetmek gerekir.

__proto__ özelliği hiç bir zaman standart olmamıştır ancak yine de Mozilla haricindeki bir çok tarayıcı bu özelliği sunmaktadır.

__proto__ özelliği, prototype özelliğinin nesne içindeki değerini değiştirmek veya elde etmek için kullanılan bir özelliktir. Bu özellik prototype özelliğin değiştirmek veya döndürmek için get ve set fonksiyonlarına sahiptir.

Örnek:

var isci = function () {
    bolum: "Üretim"
};

var kisi = {
    adi: "Mehmet",
    soyadi: "Emre"
};

isci.__proto__ = kisi;

console.log(isci.adi);    // Mehmet yazar.
veya
var kisi = { adi: 'Ali' };
var isci = {};
isci.__proto__ = kisi;

console.log(isci.adi);  // Ali yazar
Görüldüğü gibi __proto__ kullanımı, objet literal olarak tanımlanan nesnelerde kullanıldığında prototype yerine geçiyor.

Eğer __proto__ gibi birşeye ihtiyacınız olursa Object.setPrototypeOf ve Object.getPrototypeOf yöntemlerini deneyin.

Örnek:

var kisi = {
    adi : "Ali"
};

var isci = function () {
};

var ustabasi = new isci();

Object.setPrototypeOf(ustabasi, kisi);

console.log(ustabasi.adi);    // Ali yazar.
Yukarıda yaptığımız uyarıyı tekrarlayalım. Eğer performans kaygınız varsa prototipleri değiştirmemeyi düşünün.

Bayağı uzun bir makale oldu. Bundan sonra yazdığımda bağlantısını buraya ekleyeceğim "JavaScript'de kalıtım, sarmalama ve diğer OOP uygulamaları" yazımı da mutlaka okumanızı tavsiye ederim.

Bu kadar. Bir eksik veya hata görürseniz lütfen bildirin.