Yıllar geçtikçe JavaScript güçlü ve uyarlanabilir bir programlama diline dönüştü ve geliştiricilerin değişen ihtiyaçlarını karşılamak için sürekli olarak gelişti.
Nispeten yeni gelişmelerden biri, programcılara diğer nesnelerdeki önemli işlemleri yakalayabilen ve değiştirebilen güçlü ve esnek nesneler oluşturma yetkisi veren Proxy nesnesidir.
Bu makale, sözdizimini, niteliklerini, tipik uygulamalarını, güçlü yönlerini, sınırlamalarını, açıklayıcı örneklerini ve önerilen yaklaşımları kapsayacak şekilde JavaScript'te Proxy'nin yeteneklerini ayrıntılı olarak ele almaktadır.
Proxy, başka bir nesneyi saran ve onun üzerindeki özelliklere erişme, atama ve silme gibi temel işlemleri engelleyen bir nesnedir. Proxy, geliştiricilerin daha çok yönlü ve sağlam kod yazmasına olanak tanıyan, JavaScript'in önemli bir yönüdür.
Bu makalenin amacı, JavaScript'te Proxy'nin sözdizimini, özelliklerini, faydalarını, dezavantajlarını, çizimlerini ve önerilen tekniklerini kapsayan kapsamlı bir anlayış sunmaktır.
JavaScript'in Proxy'si, diğer nesneler üzerinde gerçekleştirilen temel işlemleri değiştirebilen ve özelleştirebilen nesnelerin oluşturulmasına olanak tanıyan bir yetenektir.
Bir Proxy nesnesi oluşturmak için iki bileşen gereklidir: bir hedef nesne ve bir işleyici nesne. Hedef nesne, operasyonların durdurulacağı nesnedir; işleyici nesne ise bu operasyonları yakalamak için kullanılan tuzakları veya yöntemleri tutmaktan sorumludur.
Temel bir Proxy nesnesinin nasıl oluşturulacağını gösteren bir örnek:
const target = { name: 'John', age: 25, }; const handler = { get: function(target, prop) { console.log(`Getting property ${prop}`); return target[prop]; }, }; const proxy = new Proxy(target, handler); console.log(proxy.name); // Getting property name // John
Bu örnekte iki özelliğe sahip bir hedef nesne oluşturuyoruz: ad ve yaş. Ayrıca hedef nesnedeki bir özelliği okumaya yönelik her türlü çabayı yakalamak için get trap içeren bir işleyici nesnesi de oluştururuz. Daha sonra hedef ve handler nesnelerini Proxy yapıcısına sağlayarak bir Proxy nesnesi üretiyoruz. Son olarak, get tuzağını çağıran ve konsola bir mesaj gönderen Proxy nesnesinin name özelliğini alırız.
Tuzaklar, hedef nesne üzerindeki işlemleri engelleyen yöntemlerdir. Proxy nesnesiyle kullanabileceğiniz get, set, has, deleteProperty ve daha fazlasını içeren çeşitli tuzaklar vardır.
En sık kullanılan tuzaklardan bazılarına kısa bir genel bakış:
get : Bu tuzak, hedef nesnedeki bir özelliği okuma girişimlerini engeller. İki argüman alır: hedef nesne ve erişilen özellik. Tuzak, özelliğin değerini döndürür.
set : Bu tuzak, hedef nesne üzerinde bir özellik oluşturmaya yönelik her türlü çabayı yakalar. Üç parametre gerektirir: hedef nesnenin kendisi, kurulmakta olan özellik ve bu özelliğin güncellenmiş değeri. Mekanizma, oluşturulmakta olan değeri değiştirme yeteneğine sahiptir veya değerin oluşturulmasını yasaklayacak bir hata üretebilir.
has : Bu tuzak, hedef nesnede bir özelliğin mevcut olup olmadığını kontrol etme girişimlerini engeller. İki argüman alır: hedef nesne ve kontrol edilen özellik. Tuzak, özelliğin mevcut olup olmadığını belirten bir boole değeri döndürür.
deleteProperty : Bu tuzak, hedef nesneden bir özelliği silme girişimlerini engeller. İki argüman alır: hedef nesne ve silinen özellik. Tuzak, özelliği silebilir veya özelliğin silinmesini önlemek için hata atabilir.
Proxy nesneleri, geçersiz kılınmalarına olanak tanıyan büyüleyici bir özelliğe sahiptir, bu da tuzaklarının artık hedef nesne üzerindeki işlemleri engellememesine neden olur. Geçersiz kılınabilecek bir Proxy nesnesi oluşturmak için Proxy.revocable()
işlevini kullanın.
İşte bir örnek:
const target = { name: 'John', age: 25, }; const handler = { get: function(target, prop) { console.log(`Getting property ${prop}`); return target[prop]; }, }; const {proxy, revoke} = Proxy.revocable(target, handler); console.log(proxy.name); // Getting property name // John revoke(); console.log(proxy.name); // Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoked
Bu örnekte, Proxy.revocable()
yöntemini kullanarak iptal edilebilir bir Proxy nesnesi oluşturuyoruz. Daha sonra get tuzağını tetikleyen ve konsola bir mesaj kaydeden Proxy nesnesinin name özelliğine erişiriz. Daha sonra revoke()
yöntemini kullanarak Proxy nesnesini iptal ederiz; bu, Proxy nesnesindeki özelliklere erişmeye yönelik sonraki girişimlerin başarısız olacağı anlamına gelir.
Proxy nesnelerinin bir başka ilginç özelliği de JavaScript'te miras kalıplarını uygulamak için kullanılabilmesidir. Bir Proxy nesnesini başka bir nesnenin prototipi olarak kullanarak özellik aramalarına müdahale edebilir ve prototip zincirinin davranışını özelleştirebilirsiniz.
İşte bir örnek:
const parent = { name: 'John', }; const handler = { get: function(target, prop) { console.log(`Getting property ${prop}`); if (!(prop in target)) { return Reflect.get(parent, prop); } return target[prop]; }, }; const child = new Proxy({}, handler); console.log(child.name); // Getting property name // John child.name = 'Bob'; console.log(child.name); // Getting property name // Bob console.log(parent.name); // John
Bu örnekte bir ana nesne tanımlanmıştır ve bir name niteliğine sahiptir. Daha sonra, alt nesnenin özelliklerine yönelik okuma isteklerini önleyen get trap'li bir işleyici nesnesi yaratırız. Tuzak, özelliğin alt nesnede mevcut olmaması durumunda ana nesneye geri dönmek için Reflect.get() yöntemini kullanır.
Daha sonra, prototip olarak bir Proxy nesnesi ve işleyici olarak işleyici nesnesini kullanarak bir alt nesne oluştururuz. Son olarak, alt nesnenin name özelliğine erişir ve onu değiştiririz; bu, tuzakları alma ve ayarlamayı etkinleştirir ve mesajları konsola kaydeder.
Proxy'nin kullanım örneklerinden biri pahalı işlev çağrılarını önbelleğe almaktır. Bu örnekte, bir işlev çağrısının sonucunu, argümanlarına dayalı olarak önbelleğe alan bir Proxy nesnesi oluşturuyoruz.
function calculateCost(price, taxRate) { console.log('Calculating cost...'); return price * (1 + taxRate); } const cache = new Map(); const proxy = new Proxy(calculateCost, { apply(target, thisArg, args) { const key = args.join('-'); if (cache.has(key)) { console.log('Returning cached result...'); return cache.get(key); } else { const result = Reflect.apply(target, thisArg, args); cache.set(key, result); return result; } }, }); console.log(proxy(10, 0.2)); // Calculating cost... 12 console.log(proxy(10, 0.2)); // Returning cached result... 12 console.log(proxy(20, 0.2)); // Calculating cost... 24 console.log(proxy(20, 0.3)); // Calculating cost... 26 console.log(proxy(20, 0.3)); // Returning cached result... 26
Bu örnekte, fiyatı ve vergi oranını alıp vergiyle birlikte maliyeti döndüren, calculateCost
adında bir fonksiyon tanımlıyoruz. Daha sonra Map
sınıfını kullanarak bir önbellek nesnesi oluşturuyoruz.
Daha sonra, apply
tuzağını kullanarak işlev çağrılarını engelleyen proxy
adı verilen bir Proxy nesnesi oluşturuyoruz. apply
tuzağı, işlev her çağrıldığında çağrılır ve işlev argümanlarını bir dizi olarak alır. Argümanları bir önbellek anahtarı oluşturmak için kullanırız ve sonucun zaten önbellekte olup olmadığını kontrol ederiz. Eğer öyleyse, önbelleğe alınan sonucu döndürürüz. Aksi takdirde sonucu hesaplayıp önbellekte saklarız.
Son olarak, farklı argümanlar kullanarak proxy
fonksiyonunu çağırıyoruz ve sonucun, aynı argümanlara sahip sonraki çağrılar için önbellekte saklandığını gözlemliyoruz.
Proxy'nin başka bir kullanım durumu da nesne özelliklerini doğrulamaktır. Bu örnekte, bir dize özelliğinin uzunluğunu doğrulayan bir Proxy nesnesi oluşturuyoruz.
const user = { name: 'John', password: 'secret', }; const proxy = new Proxy(user, { set(target, prop, value) { if (prop === 'password' && value.length < 8) { throw new Error('Password must be at least 8 characters long'); } target[prop] = value; return true; }, }); console.log(proxy.name); // John console.log(proxy.password); // secret proxy.password = '12345678'; console.log(proxy.password); // 12345678 proxy.password = '123'; // Error
Bu örnekte user
isimli bir nesneyi name
ve password
özelliği ile tanımlıyoruz. Daha sonra, set
tuzağı kullanarak özellik atamalarını engelleyen proxy
adı verilen bir Proxy nesnesi yaratırız. set
trap, bir özellik atandığında çağrılır ve özellik adını, yeni değeri ve hedef nesneyi alır.
Atanan özelliğin password
özelliği olup olmadığını ve değerin 8 karakterden kısa olup olmadığını kontrol etmek için set
trap'i kullanırız. Eğer öyleyse hata atarız. Aksi halde hedef nesnenin özellik değerini ayarlıyoruz.
password
özelliğine çeşitli değerler atamak için proxy
nesnesini kullanırız ve uzunluğu 8 karakterin altındaki herhangi bir değerin bir hatayı tetiklediğini unutmayın.
Proxy'nin diğer bir yaygın kullanım durumu, nesne özelliği erişimlerini ve atamalarını günlüğe kaydetmektir. Bu örnekte, özellik erişimlerini ve atamalarını günlüğe kaydeden bir Proxy nesnesi oluşturuyoruz.
const user = { name: 'John', email: '[email protected]', }; const proxy = new Proxy(user, { get(target, prop) { console.log(`Getting ${prop} property`); return target[prop]; }, set(target, prop, value) { console.log(`Setting ${prop} property to ${value}`); target[prop] = value; return true; }, }); console.log(proxy.name); // Getting name property -> John proxy.email = '[email protected]'; // Setting email property to [email protected] console.log(proxy.email); // Getting email property -> [email protected]
Bu örnekte, user
adı verilen bir nesneyi, name
ve email
özelliğiyle tanımlıyoruz. Daha sonra get
ve set
tuzaklarını kullanarak özellik erişimlerini ve atamalarını engelleyen proxy
adı verilen bir Proxy nesnesi yaratırız.
get
trap, bir özelliğe her erişildiğinde çağrılır ve özellik adını ve hedef nesneyi alır. Bu örnekte, özelliğe erişildiğini belirten bir mesajı konsola kaydediyoruz ve ardından hedef nesneden özellik değerini döndürüyoruz.
set
trap, bir özellik atandığında çağrılır ve özellik adını, yeni değeri ve hedef nesneyi alır. Bu örnekte, özelliğin atandığını belirten bir mesajı konsola kaydediyoruz ve ardından hedef nesne üzerinde özellik değerini ayarlıyoruz.
Son olarak proxy
nesnesini kullanarak çeşitli özelliklere erişip atadık ve mesajların konsola kaydedildiğini gözlemledik.
Özelleştirilebilir davranış : Proxy nesneleri ile diğer nesnelerdeki temel işlemleri engelleyebilir ve özelleştirebilir, böylece erişim kontrolü, önbelleğe alma ve günlüğe kaydetme gibi gelişmiş özellikler oluşturmanıza olanak tanır.
Kalıtım : Proxy nesneleri, JavaScript'te miras kalıplarını uygulama yeteneği sunar; bu da daha çok yönlü ve ölçeklenebilir koda yol açabilir.
İptal edilebilir : Proxy nesneleri oluşturulduktan sonra devre dışı bırakılabilir veya iptal edilebilir, bu da onları proxy nesnesinin kapsamını sınırlamak veya güvenlik nedenleriyle kullanışlı hale getirir.
Proxy'nin uzun süredir bizimle birlikte olmasına rağmen tarayıcıların tüm sürümleri bu işlevi desteklemiyor.
Üstelik Proxy kullanımı, özellikle de çok sık kullanıyorsanız uygulamanızın performansını olumsuz etkileyebilir.
Proxy kullanmanın anlamını anlamak önemlidir. Kullanıcı girişinin önemli şekilde doğrulanması gibi uygulama açısından kritik anlarda buna güvenilmemelidir.
Kısıtlamaların farkında olun : Kodunuza bir proxy uygulamadan önce, onun getirdiği kısıtlamaların ve bunların uygulamanızın hızını ve güvenliğini nasıl etkileyebileceğinin farkında olun.
Proxy nesneleri kodunuzun performansını etkileyebileceğinden yalnızca kesinlikle gerekli olduğunda kullanılmalıdır.
Dikkatlice test edin : Proxy nesnelerini kullanırken dikkatli bir şekilde test ettiğinizden ve olası beklenmeyen davranışlara karşı tetikte olduğunuzdan emin olun.
Normlara uyun : Kodunuzun okunmasını ve bakımını kolaylaştırmak için Proxy nesnelerini uygularken kabul edilen kurallara ve en iyi uygulamalara uyun.
Makalede, kalıtım kalıpları ve iptal edilebilir Proxy nesneleri oluşturma yeteneği gibi Proxy'nin gelişmiş özellikleri ele alınmaktadır.
Bir geliştirici olarak deneyim seviyeniz ne olursa olsun, JavaScript'te Proxy'yi anlamak, kodunuzu daha yüksek bir seviyeye yükseltmek için çok önemlidir.
Uyarlanabilirliği ve gücü nedeniyle Proxy, karmaşık uygulamaları kolaylıkla oluşturmayı amaçlayan herhangi bir JavaScript geliştiricisi için kritik bir araç oluşturur.