[Çeviri] Nedir bu Javascripteki “Value ve Reference Types” dedikleri şey?

119

Bu makale Arnav Aggarwal tarafından yazılan Explaining Value vs. Reference in Javascript makalesinin Türkçe çevirisidir. Makaleyi orijinal dilinde okumak için aşağıdaki linki tıklayabilirsiniz.

Başlıyoruz…


Bilgisayar belleğine basit bir bakış neler olduğunu açıklıyor.

Bu makale Step Up Your JS: A Comprehensive Guide to Intermediate JavaScript online kursumdan bir bölümdür. Makalede bulunan kodları deneyebileceğiniz ve içinde küçük bir sınavın bulunduğu içeriğe buradan bakabilirsiniz.

Javascript’te passed by value tipinde, beş tane veri tipi mevcuttur. Bunlar: BooleannullundefinedString ve Number. Bu veri tiplerine primitif tipdiyoruz.

Ayrıca Javascript’te passed by reference tipinde, 3 üç tane veri tipi vardır. Bunlar: ArrayFunction, ve Object. Bunlar temelde Nesnedir(Object), bu yüzden hepsine Nesne(Object) diyeceğiz.

Primitifler

Eğer primitif bir veri tipi, bir değişkene atanırsa, bu değişkeni primitif değeri içeren olarak düşünebiliriz.

x10’u içerir.y; 'abc'’yi içerir. Bu durumu daha iyi anlamak için, bu değişkenlerin ve bunların ilgili değerlerinin bellekte nasıl göründüğünün bir görüntüsünü koyacağız.

Bu değişkenleri = kullanarak başka bir değişkenlere atadığımız zaman; yeni değişkenlere değerleri kopyalıyoruz. Bu değişkenler copeid by value’dir.

a and x değişkenleri 10 değerini içeriyor. b and y değişlenleri de 'abc'değerini içeriyor. Değerler kopyalandığı için, hepsi birbirinden ayrıdırlar.

Bir değişkenin değerini değiştirmek, diğerinin değerini değiştirmeyecektir. Değişkenlerin birbirleri ile herhangi bir ilişkileri yok gibi düşünebiliriz.

Nesneler(Objects)

Bu bölüm biraz kafa karıştırıcı gibi gelebilir ama bana katlanıp, okumaya devam ederseniz, ne kadar kolay olduğunu göreceksiniz.

Değişkenler; primitif olmayan bir değişkene atandığı zaman, bu değere bir referans verilir. Nesnenin hafızadaki konumuna işaret eder. Bu değişken aslında değişkeni gerçekte içermez.

Nesneler, bilgisayarınızın belleğinde bir noktada yaratılır. arr = []yazdığımız zaman, bellekte bir dizi(array) yaratmış oluyoruz. arr değişkenin aldığı adres, dizinin bellekteki konumudur.

address değişkeninin, passed by value(number veya string)tipinde olan yeni bir veri türü olduğunu varsayalım. address; referans tarafından geçirilen( passed by reference) bir değerin bellekteki konumuna işaret eder. Tıpkı stringlerin tırnak işaretleri ('' veya "") ile gösterildiği gibi, address‘in değeri<> şeklinde gösterilecek.

Aşağıdaki gibi, bir reference-type tipinde bir değişken tanımlayıp ve atama işlemi yaptığımızda:

1 ve 2 numaralı satırların bellekteki durumu şu şekilde olacaktır:

1.

2.

Değişkenin değerini ve adres bilgisini içeren, arr’in static olduğuna dikkat ediniz. Bellekte bulunan dizide işlem yapıldığında neler değişir? arrdizisinde bir şeyler yaptığımızda, örneğin diziye yeni bir değer eklediğimizde(push), JavaScript motoru, arr’in bellekteki yerine gider ve burada tutulan bilgiye işlem yapar.

Assigning by Reference

Reference type tipindeki bir nesne; = kullanılarak bir değişkene kopyalandığı zaman, değerin kendisi değil nesnenin bellekteki adresi kopyalanır.

Yukarıdaki satırların bellekteki durumu şu şekildedir.

Her iki değişken de aynı dizinin referansını içerir. Bu demektir ki; eğer reference değişkenini değiştirirsek aynı değişiklikleri refCopy değişkeninde de göreceğiz.

2 değerini bellekteki diziye ekledik(push). reference ve refCopy’yi kullandığımızda bellekteki aynı diziye işaret ediyoruz.

Reassigning a Reference

Bir referans değişkenine yeni atama yapıldığında, yapılan işlem eski referans değerinin yerini alır.

Bellekte:

Aşağıdaki satırı eklediğimizde:

obj nesnesinin bellekteki adresi değişir. Birinci ve işlem yapılan yeni nesne halen bellektedir:

Yukarıdaki #234 adresine referans eden bir nesne olmadığından; Javascript motoru garbage collection’ı çalıştırır. Bunun anlamı; yazılımcı bu nesneye ait bütün referansları kaybeder ve nesneyi artık kullanamaz. Bu yüzden motor hafızadan ilgili bilgiyi güvenle siler. Bu senaryoda; { first: 'reference' }nesnesi artık erişilebilir ve mevcut olmadığından, garbage collection devreye girer.

== ve ===

Referans type nesneler için == ve === operatörleri kullanıldığı zaman, bu operatörler sadece referansı kontrol eder. Eğer değişkenler aynı referans bilgisini içeriyorsa karşılaştırma true olur.

Aynı özellikleri içeren nesneler ayrık/farklı ise, karşılaştırma false olur.

Eğer aynı özelliklere sahip iki farklı nesnemiz varsa; Karşılaştırma yapmak için en kolay yöntem bu değişkenleri string’e çevirmektir. Eşitlik operatörleri primitif tipleri karşılaştırırken, sadece değerler aynı mı diye kontrol eder.

Diğer seçenek ise, iç içe yinelemeli döngüler ile nesnenin tüm elemanlarının aynı olup olmadığı kontrol edilmesidir.

Parametrelerin fonksiyonlardan geçirilmesi

Primitif bir değer bir fonksiyona parametre olarak geçtiğimizde, fonksiyon parametre değerini kopyalar. = ile yapılan işlemle aynıdır.

Yukarıdaki örnekte; hundred değişkenine 100 değerini veriyoruz. Daha sonra hundred değişkenini multiply fonksiyona parametre olarak verdiğimizde, x değişkeni 100 değerini alır. Sanki = ile yapılan atama işlemi yapılıyormuş gibi değer kopyalandı. hundred değişkeni bu durumdan etkilenmez. multiply fonksiyonundaki PAUSE yorum satırında; değişkenlerin bellekteki durumu ile ilgili anlık görüntü şu şekildedir.

Pure Functions

Dış kapsamdaki(the outside scope) hiçbir şeye etki etmeyen fonksiyonlara Pure Fonksiyon denir. Bir fonksiyon, parametre olarak yalnız primitif değer alıyor ve iç kapsamda bunu kullanmıyor ayrıca dış kapsamdaki hiç bir şeyi etkilemiyorsa, otomatik olarak bu fonksiyon pure fonksiyondur. Fonksiyon değer döner dönmez; fonksiyonun içinde yaratılan tüm değişkenler garbage-collected olarak işlem görür.

Bir fonksiyon parametre olarak nesne de alabilir. Bununla birlikte nesnenin durumu fonksiyon kapsamında(scope) değişebilir. Eğer bir fonksiyon parametre olarak diziyi referans ediyorsa ve fonksiyonun içerisinde bu dizinin işaret ettiği noktadaki değeri değiştiriyorsa(diziye bir eleman ekleyebilir), referans edilen dizi de aynı değişiklileri görecektir. Fonksiyon değer döndükten sonra da değişiklikler dış kapsamda devam edecektir. Bu durum takip edilmesi güç ve istenilmeyen yan etkilere(side effects) sebep olabilir.

Bir çok Dizi(Array) fonksiyonu, örneğin Array.map ve Array.filter, pure fonksiyon olarak yazılmıştır. Parametre olarak dizi referansı alırlar ve içeride dizinin bir kopyasını oluşturup, orijinal dizinin yerine ,bu kopya üzerinden işlemlerini yapar. Bu fonksiyonlar(map, filter vb); referans edilen diziye hiç dokunmadan, dış kapsam etkilemeden, yeni bir dizi döner.

Pure fonksiyonla anlamak için, aşağıdaki pure olmayan fonksiyon örneğine bakalım.

Bu pure olmayan fonksiyon bir nesne alıyor ve nesnedeki age özelliğini 25 olarak değiştiriyor. Bu işlemden dolayı referans olarak verilen nesne de bu değişiklikten etkileniyor. Dikkat ederseniz fonksiyon kendisine referans olarak verilen personnesnesini işlemin sonunda geri dönüyor. alex ve alexChanged değişkenleri aynı referansı içermektedir. Bu yüzdendir ki fonksiyondan dönen person değişkenini yeni bir değişkende tutmak gereksizdir.

Şimdi de pure fonksiyon örneğine bakalım

Bu fonksiyonda, parametre olarak geçtiğimiz nesneyi string’e dönüştürmek için JSON.stringify’yi ve daha sonra nesneye dönüştürmek için sonra JSON.parse’yi kullanıyoruz. Bu dönüşüm ile sonucu yeni bir değişkende tutarak yeni bir nesne yaratıyoruz. Aynı işlem farklı yöntemlerle de yapılabilir, mesela nesnenin tüm özellikleri döngü ile yeni bir özelliğe aktarılabilir, ama bu yöntem en kolayıdır. Yeni nesne aynı özelliklere sahip olmasına rağmen bu nesneler bellekte birbirinden ayrıdır.

Yeni nesnedeki age özelliğini değiştirdiğimizde, orijinal nesne bu durumdan etkilenmez. Bu fonksiyon şimdi pure fonksiyon oldu. Parametre olarak bir nesne geçsek bile, fonksiyon kendi kapsamı dışındaki hiç bir nesneyi etkilemiyor. Bu fonksiyondan dönen değeri tutmak için yeni bir nesneye ihtiyacımız var. Aksi durumda garbage collection, fonksiyon işlemi tamamladıktan sonra nesneyi silecektir. Ve nesne kapsamda olmayacaktır.

Kendiniz Test Edin

Value ve Refence; yazılım iş görüşmelerinde sıklıkla sorulan bir konudur. Aşağıdaki örnekte neyi logladığımızı anlamak için kendiniz deneyin.

Fonksiyon, parametre olarak geçilen orijinal nesnenin age özelliğini değiştiriyor. Daha sonra bu nesneye yeni bir nesne ataması yapıyor ve bu nesneyi dönüyor. İşte logladığımız iki nesne şu şekildedir.

Bir fonksiyona parametre geçmek; = değer ataması ile işlem yapmakla aynı olduğunu hatırlayın. Fonksiyondaki person değişkeni, personObj1nesnesinin bir referansını içerdiğinden, yapılan tüm işlemler öncelikle nesneyi doğrudan etkiler. person değişkenini yeni bir nesneye atadığımız için orijinal nesnenin yapılan işlemlerden etkilenmesi durdu ama bu atama personObj1nesnesini değiştirmedi.

Yukarıdaki kod parçasının eşleniği şu şekilde olabilir:

Eğer bu makale sizin için faydalı olmuş ise, lütfen beğeni butonuna basınız ve diğer çalışmalarıma bakabilirsiniz

Çalışmalarım

Online kurs

educative.io de orta seviye javascript konuları olan scope, closures, OOP, thisnewapply/call/bind, asynchronous code, array and object manipulation, and ES2015+ içi bir kurs hazırladım.

Son Makaleler


Çeviri notları:

Makalede gözünüze çarpan çeviri hatalarını iletirseniz gerekli düzenlemeleri yaparım. Başka bir çeviride görüşmek üzere.

Yorum yaz

Email adresiniz yayınlanmayacaktır.