Türkçe

JavaScript Proxy nesneleriyle veri doğrulama, sanallaştırma ve performans optimizasyonu gibi gelişmiş teknikleri öğrenin. Esnek kodlar için nesne işlemlerini yakalayın.

Gelişmiş Veri Manipülasyonu için JavaScript Proxy Nesneleri

JavaScript Proxy nesneleri, temel nesne işlemlerini yakalamak ve özelleştirmek için güçlü bir mekanizma sağlar. Nesnelere nasıl erişildiği, değiştirildiği ve hatta oluşturulduğu üzerinde hassas kontrol kurmanıza olanak tanır. Bu yetenek, veri doğrulama, nesne sanallaştırma, performans optimizasyonu ve daha fazlası gibi ileri düzey tekniklerin kapılarını aralar. Bu makale, JavaScript Proxy'lerinin dünyasına dalarak yeteneklerini, kullanım alanlarını ve pratik uygulamalarını keşfedecektir. Küresel geliştiricilerin karşılaştığı çeşitli senaryolarda uygulanabilir örnekler sunacağız.

JavaScript Proxy Nesnesi Nedir?

Özünde bir Proxy nesnesi, başka bir nesnenin (hedefin) etrafındaki bir sarmalayıcıdır. Proxy, hedef nesne üzerinde gerçekleştirilen işlemleri yakalar ve bu etkileşimler için özel davranışlar tanımlamanıza olanak tanır. Bu yakalama işlemi, belirli işlemlerin nasıl ele alınması gerektiğini tanımlayan yöntemler (tuzaklar olarak adlandırılır) içeren bir işleyici nesnesi aracılığıyla gerçekleştirilir.

Şu benzetmeyi düşünün: Değerli bir tablonuz olduğunu hayal edin. Onu doğrudan sergilemek yerine, bir güvenlik ekranının (Proxy) arkasına yerleştirirsiniz. Ekranın, birisi tabloya dokunmaya, hareket ettirmeye ve hatta bakmaya çalıştığında algılayan sensörleri (tuzaklar) vardır. Sensörün girdisine dayanarak, ekran daha sonra hangi eylemi gerçekleştireceğine karar verebilir – belki etkileşime izin verir, onu günlüğe kaydeder veya hatta tamamen reddeder.

Temel Kavramlar:

Bir Proxy Nesnesi Oluşturma

Bir Proxy nesnesini, iki argüman alan Proxy() yapıcısı kullanarak oluşturursunuz:

  1. Hedef nesne.
  2. İşleyici nesne.

İşte temel bir örnek:

const target = {
  name: 'John Doe',
  age: 30
};

const handler = {
  get: function(target, property, receiver) {
    console.log(`Getting property: ${property}`);
    return Reflect.get(target, property, receiver);
  }
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // Çıktı: Getting property: name
                         //         John Doe

Bu örnekte, get tuzağı işleyicide tanımlanmıştır. proxy nesnesinin bir özelliğine erişmeye çalıştığınızda, get tuzağı çağrılır. Reflect.get() yöntemi, işlemi hedef nesneye iletmek için kullanılır ve varsayılan davranışın korunmasını sağlar.

Yaygın Proxy Tuzakları

İşleyici nesnesi, her biri belirli bir nesne işlemini yakalayan çeşitli tuzaklar içerebilir. İşte en yaygın tuzaklardan bazıları:

Kullanım Alanları ve Pratik Örnekler

Proxy nesneleri, çeşitli senaryolarda geniş bir uygulama yelpazesi sunar. Pratik örneklerle en yaygın kullanım alanlarından bazılarını inceleyelim:

1. Veri Doğrulama

Özellikler ayarlandığında veri doğrulama kurallarını zorunlu kılmak için Proxy'leri kullanabilirsiniz. Bu, nesnelerinizde saklanan verilerin her zaman geçerli olmasını sağlayarak hataları önler ve veri bütünlüğünü artırır.

const validator = {
  set: function(target, property, value) {
    if (property === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('Yaş bir tamsayı olmalıdır');
      }
      if (value < 0) {
        throw new RangeError('Yaş negatif olmayan bir sayı olmalıdır');
      }
    }

    // Özelliği ayarlamaya devam et
    target[property] = value;
    return true; // Başarıyı belirt
  }
};

const person = new Proxy({}, validator);

try {
  person.age = 25.5; // TypeError fırlatır
} catch (e) {
  console.error(e);
}

try {
  person.age = -5;   // RangeError fırlatır
} catch (e) {
  console.error(e);
}

person.age = 30;   // Sorunsuz çalışır
console.log(person.age); // Çıktı: 30

Bu örnekte, set tuzağı, ayarlanmasına izin verilmeden önce age özelliğini doğrular. Değer bir tamsayı değilse veya negatifse, bir hata fırlatılır.

Küresel Bakış Açısı: Bu, yaş gösterimlerinin farklılık gösterebileceği çeşitli bölgelerden kullanıcı girdisini işleyen uygulamalarda özellikle kullanışlıdır. Örneğin, bazı kültürler çok küçük çocuklar için kesirli yılları içerebilirken, diğerleri her zaman en yakın tam sayıya yuvarlar. Doğrulama mantığı, veri tutarlılığını sağlarken bu bölgesel farklılıklara uyum sağlayacak şekilde uyarlanabilir.

2. Nesne Sanallaştırma

Proxy'ler, yalnızca gerçekten ihtiyaç duyulduğunda veri yükleyen sanal nesneler oluşturmak için kullanılabilir. Bu, özellikle büyük veri setleri veya kaynak yoğun işlemlerle uğraşırken performansı önemli ölçüde artırabilir. Bu, bir tür geç yüklemedir (lazy loading).

const userDatabase = {
  getUserData: function(userId) {
    // Bir veritabanından veri almayı simüle et
    console.log(`ID için kullanıcı verileri getiriliyor: ${userId}`);
    return {
      id: userId,
      name: `Kullanıcı ${userId}`,
      email: `kullanici${userId}@example.com`
    };
  }
};

const userProxyHandler = {
  get: function(target, property) {
    if (!target.userData) {
      target.userData = userDatabase.getUserData(target.userId);
    }
    return target.userData[property];
  }
};

function createUserProxy(userId) {
  return new Proxy({ userId: userId }, userProxyHandler);
}

const user = createUserProxy(123);

console.log(user.name);  // Çıktı: ID için kullanıcı verileri getiriliyor: 123
                         //         Kullanıcı 123
console.log(user.email); // Çıktı: kullanici123@example.com

Bu örnekte, userProxyHandler özellik erişimini yakalar. user nesnesinde bir özelliğe ilk kez erişildiğinde, kullanıcı verilerini almak için getUserData fonksiyonu çağrılır. Diğer özelliklere sonraki erişimler, zaten alınmış olan verileri kullanacaktır.

Küresel Bakış Açısı: Bu optimizasyon, ağ gecikmesi ve bant genişliği kısıtlamalarının yükleme sürelerini önemli ölçüde etkileyebileceği dünya genelindeki kullanıcılara hizmet veren uygulamalar için çok önemlidir. Yalnızca gerekli verileri talep üzerine yüklemek, kullanıcının konumundan bağımsız olarak daha duyarlı ve kullanıcı dostu bir deneyim sağlar.

3. Günlük Kaydı ve Hata Ayıklama

Proxy'ler, hata ayıklama amacıyla nesne etkileşimlerini günlüğe kaydetmek için kullanılabilir. Bu, hataları izlemede ve kodunuzun nasıl davrandığını anlamada son derece yardımcı olabilir.

const logHandler = {
  get: function(target, property, receiver) {
    console.log(`GET ${property}`);
    return Reflect.get(target, property, receiver);
  },
  set: function(target, property, value, receiver) {
    console.log(`SET ${property} = ${value}`);
    return Reflect.set(target, property, value, receiver);
  }
};

const myObject = { a: 1, b: 2 };
const loggedObject = new Proxy(myObject, logHandler);

console.log(loggedObject.a);  // Çıktı: GET a
                            //         1
loggedObject.b = 5;         // Çıktı: SET b = 5
console.log(myObject.b);    // Çıktı: 5 (orijinal nesne değiştirilir)

Bu örnek, her özellik erişimini ve değişikliğini günlüğe kaydederek nesne etkileşimlerinin ayrıntılı bir izini sağlar. Bu, hataların kaynağını izlemenin zor olduğu karmaşık uygulamalarda özellikle yararlı olabilir.

Küresel Bakış Açısı: Farklı saat dilimlerinde kullanılan uygulamalarda hata ayıklarken, doğru zaman damgalarıyla günlük kaydı yapmak esastır. Proxy'ler, saat dilimi dönüşümlerini yöneten kütüphanelerle birleştirilebilir, bu da günlük girişlerinin kullanıcının coğrafi konumundan bağımsız olarak tutarlı ve analiz edilmesi kolay olmasını sağlar.

4. Erişim Kontrolü

Proxy'ler, bir nesnenin belirli özelliklerine veya yöntemlerine erişimi kısıtlamak için kullanılabilir. Bu, güvenlik önlemleri uygulamak veya kodlama standartlarını zorunlu kılmak için kullanışlıdır.

const secretData = {
  sensitiveInfo: 'Bu gizli bir veridir'
};

const accessControlHandler = {
  get: function(target, property) {
    if (property === 'sensitiveInfo') {
      // Yalnızca kullanıcı kimliği doğrulanmışsa erişime izin ver
      if (!isAuthenticated()) {
        return 'Erişim reddedildi';
      }
    }
    return target[property];
  }
};

function isAuthenticated() {
  // Kendi kimlik doğrulama mantığınızla değiştirin
  return false; // Veya kullanıcı kimlik doğrulamasına göre true
}

const securedData = new Proxy(secretData, accessControlHandler);

console.log(securedData.sensitiveInfo); // Çıktı: Erişim reddedildi (kimlik doğrulanmamışsa)

// Kimlik doğrulamayı simüle et (gerçek kimlik doğrulama mantığıyla değiştirin)
function isAuthenticated() {
  return true;
}

console.log(securedData.sensitiveInfo); // Çıktı: Bu gizli bir veridir (kimlik doğrulanmışsa)

Bu örnek, yalnızca kullanıcı kimliği doğrulanmışsa sensitiveInfo özelliğine erişime izin verir.

Küresel Bakış Açısı: Erişim kontrolü, GDPR (Avrupa), CCPA (Kaliforniya) ve diğerleri gibi çeşitli uluslararası düzenlemelere uygun olarak hassas verileri işleyen uygulamalarda çok önemlidir. Proxy'ler, bölgeye özgü veri erişim politikalarını zorunlu kılarak kullanıcı verilerinin sorumlu bir şekilde ve yerel yasalara uygun olarak işlenmesini sağlar.

5. Değişmezlik (Immutability)

Proxy'ler, kazara yapılan değişiklikleri önleyerek değişmez nesneler oluşturmak için kullanılabilir. Bu, veri değişmezliğinin çok değerli olduğu fonksiyonel programlama paradigmalarında özellikle kullanışlıdır.

function deepFreeze(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  const handler = {
    set: function(target, property, value) {
      throw new Error('Değişmez nesne değiştirilemez');
    },
    deleteProperty: function(target, property) {
      throw new Error('Değişmez nesneden özellik silinemez');
    },
    setPrototypeOf: function(target, prototype) {
      throw new Error('Değişmez nesnenin prototipi ayarlanamaz');
    }
  };

  const proxy = new Proxy(obj, handler);

  // İç içe nesneleri yinelemeli olarak dondur
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      obj[key] = deepFreeze(obj[key]);
    }
  }

  return proxy;
}

const immutableObject = deepFreeze({ a: 1, b: { c: 2 } });

try {
  immutableObject.a = 5; // Hata fırlatır
} catch (e) {
  console.error(e);
}

try {
  immutableObject.b.c = 10; // Hata fırlatır (çünkü b de dondurulmuştur)
} catch (e) {
  console.error(e);
}

Bu örnek, özelliklerinde veya prototipinde herhangi bir değişikliği önleyerek derinden değişmez bir nesne oluşturur.

6. Eksik Özellikler için Varsayılan Değerler

Proxy'ler, hedef nesnede bulunmayan bir özelliğe erişmeye çalışıldığında varsayılan değerler sağlayabilir. Bu, tanımsız özellikleri sürekli kontrol etme ihtiyacını ortadan kaldırarak kodunuzu basitleştirebilir.

const defaultValues = {
  name: 'Bilinmiyor',
  age: 0,
  country: 'Bilinmiyor'
};

const defaultHandler = {
  get: function(target, property) {
    if (property in target) {
      return target[property];
    } else if (property in defaultValues) {
      console.log(`${property} için varsayılan değer kullanılıyor`);
      return defaultValues[property];
    } else {
      return undefined;
    }
  }
};

const myObject = { name: 'Alice' };
const proxiedObject = new Proxy(myObject, defaultHandler);

console.log(proxiedObject.name);    // Çıktı: Alice
console.log(proxiedObject.age);     // Çıktı: age için varsayılan değer kullanılıyor
                                  //         0
console.log(proxiedObject.city);    // Çıktı: undefined (varsayılan değer yok)

Bu örnek, orijinal nesnede bir özellik bulunmadığında varsayılan değerlerin nasıl döndürüleceğini gösterir.

Performans Değerlendirmeleri

Proxy'ler önemli esneklik ve güç sunarken, potansiyel performans etkilerinin farkında olmak önemlidir. Nesne işlemlerini tuzaklarla yakalamak, özellikle performansa duyarlı uygulamalarda performansı etkileyebilecek ek yük getirir.

Proxy performansını optimize etmek için bazı ipuçları:

Tarayıcı Uyumluluğu

JavaScript Proxy nesneleri, Chrome, Firefox, Safari ve Edge dahil olmak üzere tüm modern tarayıcılarda desteklenmektedir. Ancak, eski tarayıcılar (örneğin, Internet Explorer) Proxy'leri desteklemez. Küresel bir kitle için geliştirme yaparken, tarayıcı uyumluluğunu göz önünde bulundurmak ve gerekirse eski tarayıcılar için yedek mekanizmalar sağlamak önemlidir.

Kullanıcının tarayıcısında Proxy'lerin desteklenip desteklenmediğini kontrol etmek için özellik tespiti kullanabilirsiniz:

if (typeof Proxy === 'undefined') {
  // Proxy desteklenmiyor
  console.log('Proxy\'ler bu tarayıcıda desteklenmiyor');
  // Bir yedek mekanizma uygulayın
}

Proxy'lere Alternatifler

Proxy'ler benzersiz bir yetenek seti sunarken, bazı senaryolarda benzer sonuçlar elde etmek için kullanılabilecek alternatif yaklaşımlar da vardır.

Hangi yaklaşımın kullanılacağı seçimi, uygulamanızın özel gereksinimlerine ve nesne etkileşimleri üzerinde ne kadar kontrole ihtiyacınız olduğuna bağlıdır.

Sonuç

JavaScript Proxy nesneleri, nesne işlemleri üzerinde hassas kontrol sunan, gelişmiş veri manipülasyonu için güçlü bir araçtır. Veri doğrulama, nesne sanallaştırma, günlük kaydı, erişim kontrolü ve daha fazlasını uygulamanıza olanak tanır. Proxy nesnelerinin yeteneklerini ve potansiyel performans etkilerini anlayarak, küresel bir kitle için daha esnek, verimli ve sağlam uygulamalar oluşturmak üzere onlardan yararlanabilirsiniz. Performans sınırlamalarını anlamak kritik olsa da, Proxy'lerin stratejik kullanımı, kodun sürdürülebilirliğinde ve genel uygulama mimarisinde önemli iyileştirmelere yol açabilir.