Javascript’in Tarihçesi

JS’te Kalıtım(Inheritance) Nasıl Gerçekleşir ?

Javascript Fonksiyonel bir dil. Class, new, extends nasıl çalışır?

--

Giriş

Bu yazıyı daha önceden yazmış olduğum Javascript’in Tarihçesi yazısının bir devamı olarak yazıyorum. Bir çok kavramı tek bir yazıda ele almanın yaratacağı karmaşıklıktan kaçmak için bu şekilde bir yönteme başvurdum. Bu yazılardaki amacım önceden Javascript’in varolan hangi özelliklerinin yetmediğini ve bu geliştirmeyle neyi hedeflediklerini anlatacağım.

Kısa bir dip not olarak şunuda belirteyim ki, aslında bu konu teknik olarak çok daha derin bir konu Scoping, Object.create, Object.assign, this, bindings, Deep/Shallow Copy vb konuları içeriyor. Ben burada işleri çok karıştırdığı için sadece işlevsel olarak amacından bahsedeceğim teknik derinliklere pek inmeyeceğim.

Özetle aşağıdaki kapsamları anlatmaya çalışacağım.

  • Obje nasıl tanımlanır ?
  • Objemize bir fonksiyon eklemeye çalışalım.
  • Prototype nedir ? Ne işe yarar ?
  • new, class ve extends nasıl çalışır ?

1. Obje Nasıl Tanımlanır ?

Kalıtımı anlatmadan önce Javascript’te Objenin nasıl tanımlandığını anlamamız gerekir.

Boş bir objeyi aşağıdaki 2 şekildede tanımlarız. 2 tanımda aynıdır.

const emptyObject={};
const anotherObject=new Object();

Aşağıdaki objemisin içerisine isim ve yas değişken olarak tutmak isteyelim. Daha nesneyi tanımlarken JSON şeklinde tanımlayabiliriz.

const onurObj={isim:”onur”, yas:12}; 

veya boş bir obje oluşturup ona .degiskenIsmi ile değişken değerlerimizi atayabiliriz.

const onurObj2={}
onurObj.isim=”Onur”
onurObj.yas=39

veya bir map objesi gibi [“degiskenIsmi”] erişerek atama yaparız.

const onurObj={}
onurObj[“isim”]=”Onur”
onurObj[“yas”]=39

Eğer amacımız tek bir obje oluşturup bunu kullanmak ise yukarıda bahsettiğimiz yöntemler oldukça kullanışlıdır. Fakat amacınız bunun gibi bir çok benzer obje oluşturmak ise örneğin ali, veli, ahmet, ayşe vb.. alt alta bu kodları tekrar tekrar kopyalamamız anlamına gelirki bu istediğimiz bir şey değildir. burda aklımıza bu nesneleri soyutlayacak bir Function Constructor oluşturabiliriz

Aşağıdaki örnekte kullanıcı(User) olarak bir fonksiyon yazıyorum ve bu fonksiyon parametrelerinde değişkenleri alıyor. Bu soyutlama sayesinde kod tekrarından kurtuluyoruz.

function User(name,age){
let user={};
user.name=name; user.age=age;
return user;
}
const onurObj=User("Onur",39);
const denizObj=User("Deniz",8);

2. Objemize Bir Fonksiyon Eklemeye Çalışalım.

User .sayHello fonksiyonu ekleyelim. Aşağıda her şey güzel gözüksede aslında istemediğimiz bir durum oluşturmuş oluruz. Her bir kullanıcı için sayHello yeni bir fonksiyon oluşturur ve bellekte bunun için ayrı bir yer tutar.

function User(name,age){
let user={};
user.name=name;
user.age=age;
user.sayHello=function(){
console.log(`My name is ${name} and I am ${age} years old.`)
}
return user;
}
const user1=User("Onur",39); console.log(user1.sayHello());
const user2=User("Deniz",8); console.log(user2.sayHello());

Bu fonksiyonu dışarda tanımlayıp içerde referansını kullanmalıyız. User ait fonksiyonları ortak bir yerde tanımlamayız özetle. commonFunctions4User içerisinde fonksiyonumuz tanımlayıp referansını sayHello değişkenine atadığımızda bellekte her method için ayrı bir yer tutma sorununu çözmüş olduk.

const commonFunctions4User={
sayHello:function(name,age){
console.log(`My name is ${name} and I am ${age} years old.`)
}
}
function User(name,age){
let user={};
user.name=name;
user.age=age;
user.sayHello=commonFunctions4User.sayHello;
return user;
}

Ama halen daha istemediğimiz bir durum ile karşı karşıyayız sayName, sayAge, sayGoodBye şeklinde metodlar eklemek istediğimizde sürekli olarak constructor function içerisinde ilgili değişkenlere atama yapmamız gerekir. Halbuki mevcut nesnemiz içerisinde bu değerler olsada direk bunları kullanabilsek. Object.create ile common fonksiyonları direk kullanıcıya atarsak yeni bir fonksiyon yazdığımızda tek tek user kullanıcısına assign etmemize gerek kalmaz.

const commonFunctions4User={
sayHello:function(){
console.log(`My name is ${this.name} and I am ${this.age} years old.`)}
}
function User(name,age){
let user=Object.create(commonFunctions4User);
user.name=name;
user.age=age;
return user;
}
const onur=User("Onur",39);
onur.sayHello();

4. Prototype Nedir ? Ne işe yarar ?

İlk başta en basit şekilde obje tanımlamaktan bahsetmiştik.

const emptyObject={};
const anotherObject=new Object();

Bu objeleri tanımladığımızda arka planda __proto__ şeklinde objeye ait bir iskelet oluşuyor. Bu yukarıda bahsettiğimiz commonFunctions4User gibi ayrı ayrı ortak fonksiyon kümeleri oluşturmakta işleri bir çok obje olduğu zaman karıştıracaktır.

An Empty Object

Burda objenin kendi prototype kullanarak bu karmaşıklıkları önleyebiliriz. Artık User nesnesi yavaş yavaş istediğimiz sınıf dönüşmeye başladı. Uzun zamandır bu prototype mantığını String vb yapılarda kendi yardımcı fonksiyonları eklemek için kullanıyordum zaten (Örneğin replaceAll, capitalize vb.) İstediğim zaman kullandığım kütüphane ve nesneleri kendime göre genişletebiliyordum. Ama prototype class ve inheritance temelini oluşturduğunu bilmiyordum.

User.prototype.sayHello=function(){
console.log(`My name is ${this.name} and I am ${this.age} years old.`)
}
function User(name,age){
let user=Object.create(User.prototype);
user.name=name;
user.age=age;
return user;
}
const onur=User("Onur",39);
onur.sayHello();

5. New, Class ve Extends Nasıl Çalışır ?

Şimdi yukarıda yazdığımız daha okunabilir yazmak için class ve new metodlarını kullanalım. Object.create ve return gerek kalmayacak, prototype class bağlamının içerisinde gösterildiğinden aşağıda kodun çok daha okunabilir bir hale geldiğini görebilirsiniz.

class User{
constructor(name,age){
this.name=name;
this.age=age
}
sayHello(){
console.log(`My name is ${this.name} and I am ${this.age} years old.`)}
}const onur=new User("Onur",39);
onur.sayHello();

Arkaplanda değişen bir şey yok ama her şey prototype üzerinden çalışıyor. Şimdi kalıtımın(inheritance) nasıl çalıştığına bir bakalım. Aşağıda 2 tane sınıf yazdım. Birisi Shape , ikincisi’de bundan türeyen Rectangle .

Rectangle extends Shape

Rectangle hiç bir metodu olmadığı halde atasındaki(parent) sayShape metodunu çalıştırabiliyoruz. Peki nasıl ?. Sorunun cevabını yine arka planda tutulan veri yapısından anlayabilirsiniz Shape içerisinde sayShape Rectangle nasıl __proto__ altındaki __proto__ kopyalandığını görebilirsiniz. Bu prototype chain(zincir) şeklinde fonksiyonları çağırararak kalıtımı sağlayabiliyor javascript. İşin sırrı burda.

In backend JS Holds Objects

Yazılarımı beğenirseniz alkışlamayı unutmayın. 👏👏👏

Referans

  1. https://tylermcginnis.com/beginners-guide-to-javascript-prototype/

Okumaya Devam Et 😃

Bu yazının devamı veya yazı grubundaki diğer yazılara erişmek için bu linke tıklayabilirsiniz.

--

--