Reference ve Primitive Değerler/Tipler

Reference ve Primitive Değerler/Tipler

2019-02-18    

Javascript dilinde veri tipleri 2 kategoriye ayrılır. Bunlar referans (Reference) ve ilkel (Primitive) veri tipleri olarak adlandırılır. Bu yazımda sizlere bu kavramları daha iyi algılamamız için örnekler vererek açıklamaya çalışıcağım. Projelermizin birçok yerinde kullandığımız değişkenler ve değişkenler üzerinde yaptığımız işlemlerin önemi açısında faydalı olacağını umarım.

Primitive Types

İlk örneğimiz:

var age = 30;

Yaş değişkeni (isterseniz let veya const kullanabilirsiniz) sayısal (Number) bir değer tutar. Sayısal değerler tutan değişkenler ilkel veri tipleridir. Basit javascript uygulamalarının yapı taşlarıdır.

Diğer basit yapı taşları:

var name = "Gürol";
var isMale = true;

Sayısal (Number), karakter katarları (String) ve doğru/yanlış (Boolean) veri tiplerini muhtemelen çok iyi biliyorsunuz. Ayrıca bunlara ek olarak undefined ve null veri tipleride ilkel (Primitive) veri tipleridir.

Reference Types

Javascript dilinde nesneler (Object) ve diziler (Array) referans veri tipleridir.

var person = {
  name: 'Gürol',
  age: 30,
}

var hobbies = ['Sports', 'Cooking']

Yukarıdaki örnekte person değişkeni bir nesnedir ve bu yüzden referans veri tipidir. Lütfen nesnenin özelliklerinin ilkel veri tipleri barındırdığına dikkat edin. Bu nesnenin bir referans tipi olmasını engellemez. Ayrıca person nesnesi içinde içiçe geçmiş nesneleri veya dizileride özellik olarak eklebilirsiniz.

hobbies dizisi de referans (Reference) tipli bir değişkendir. Yukarıdaki durumda karakter katarı (String) barındıran bir dizidir. Karekter katarları primitive veri tipleridir fakat dizi içinde yer alması durumu etkilemez. Diziler her zaman referans tipli değişkenlerdir.

Farkları Nedir?

Harika, şimdi elimizde iki farklı kategorimiz var. Buradaki amaç elbette ki bellek (Memory Management) yönetimidir.

Javascript, değişkenlere atadığımız değerleri bellekte saklamak zorundadır. Javascript'de iki tip bellek alanı vardır. Bunlar stack ve heap alanlarıdır. Bu konuda daha derin bir yazı okumak istersen buraya gidebilirisin.

Kısa özet: Stack aslında kolay erişilebilen basit yönetilen bir alandır. Sadece büyüklüğü belli olan değişkenler stack alanında saklanır. Bunlar numbers, string ve boolean veri tipleridir.

Boyutu ve yapısı belli olmayan veri tipleri heap alanında saklanır. Nesneler (object) ve diziler (array) çalışma zamanında mutasyona uğrayabilirler bu nedenle heap alanında saklanırlar.

Açıkcası daha bir çok farkları olmasına rağmen en temel farkları bunlardır.

Heap alanında saklanan her bir öğe için, stack alanında bir gösterge (pointer) saklanır. Bu bilgiyi kafanıza kazımanızda fayda vardır.

alt text

Peki bu biz geliştiriciler için ne gibi bir farklılık yaratır.

Referans Tiplerindeki Garip Davranışlar

Referans tiplerinin yerlerinin göstergeleri stack alanında saklanması çok önemlidir. Yukarıdaki şekilde görüldüğü gibi person değişkeninin heap alanındaki yeri stack alanındaki göstergesinde tutulur. Şimdi bu durumun başımıza neler açtığına aşağıdaki kod parçasıyla bakalım.

var person = { name: 'Gürol' }
var newPerson = person
newPerson.name = 'Ali Mete'
console.log(person.name); // output: Ali Mete

Nasıl yani?

Çünkü person nesnesini newPerson nesnesine kopyalamadık. Sadece göstergesini kopyaladık. O hala heap bölgesinde tek bir alanda saklanıyor. Bu durumda biz newPerson nesnesinde bir değişiklik yaptığımızda person nesnesini de etkilemiş olduk.

Bu durumu iyi anlamamız gerekiyor!

Diziler içinde aynı durum geçerlidir.

var hobbies = ['Sports', 'Cooking'];
var copiedHobbies = hobbies;
copiedHobbies.push('Music');
console.log(hobbies[2]); // output: Music

Gerçek Değerleri Nasıl Kopyalabiliriz?

Artık nesne veya dizileri birbirine eşitlediğimizde aslında onların göstergelerini kopyaladığımızı biliyoruz. Şimdi nasıl gerçek değerleri kopyalacağımızı öğrenelim.

Aslında yapmamız gereken işlem yeni bir nesne veya dizi oluşturmamızdır. Bunun için birkaç farklı yöntem vardır. Aşağıda en basit ve hızlı kullanımları ele aldım.

slice() method;

var hobbies = ['Sports', 'Cooking'];
var copiedHobbies = hobbies.slice();

spread operator

var hobbies = ['Sports', 'Cooking'];
var copiedHobbies = [...hobbies];

var person = { name: 'Gürol' };
var copiedPerson = { ...person };

Object.assign()

var person = { name: 'Gürol' };
var copiedPerson = Object.assign({}, person);

Derinlemesine Kopyalama

Burada önemli bir bilgi vermek istiyorum. Yukarıdaki yaklaşımların hiçbiri derinlemesine kopyalama yapmaz. Kopyalamak istediğiniz dizi veya nesne içerisinde iç içe nesneler veya iç içe diziler varsa bunlar kopyalanmayacaktır. Bunların sadece göstergeleri kopyalanır. Aşağıdaki örneği kendiniz uygulamaya çalışın.

var data = [
    { id: 1, values: { a: 'a', b: 'b' } },
    { id: 2, values: { c: 'c', d: 'd' } }
];

var newData = data.slice();

data[1].values.d = 'x';

console.log(newData): // output: [{"id":1,"values":{"a":"a","b":"b"}},{"id":2,"values":{"c":"c","d":"x"}}]

Bunlar için metodlar yazıp kullanabilirsiz veya populer javascript kütüphanelerinden faydalanabilirsiz.

Lodash Deep Clone