वैश्विक डेवलपर्स के लिए JavaScript Proxy API में महारत हासिल करने के लिए एक व्यापक गाइड। व्यावहारिक उदाहरणों, उपयोग के मामलों और प्रदर्शन युक्तियों के साथ ऑब्जेक्ट संचालन को इंटरसेप्ट और अनुकूलित करना सीखें।
JavaScript Proxy API: ऑब्जेक्ट व्यवहार संशोधन में एक गहन गोता
आधुनिक JavaScript के विकसित परिदृश्य में, डेवलपर्स लगातार डेटा के साथ अधिक शक्तिशाली और सुरुचिपूर्ण तरीके से बातचीत करने के तरीके खोज रहे हैं। जबकि क्लास, मॉड्यूल और एसिंक/अवेट जैसी सुविधाओं ने हमारे कोड लिखने के तरीके में क्रांति ला दी है, ECMAScript 2015 (ES6) में पेश की गई एक शक्तिशाली मेटाप्रोग्रामिंग सुविधा है जो अक्सर कम उपयोग की जाती है: Proxy API।
मेटाप्रोग्रामिंग डराने वाला लग सकता है, लेकिन यह केवल दूसरे कोड पर काम करने वाले कोड को लिखने की अवधारणा है। Proxy API इसके लिए JavaScript का प्राथमिक उपकरण है, जो आपको किसी अन्य ऑब्जेक्ट के लिए एक 'प्रॉक्सी' बनाने की अनुमति देता है, जो उस ऑब्जेक्ट के लिए मौलिक संचालन को इंटरसेप्ट और पुनः परिभाषित कर सकता है। यह किसी ऑब्जेक्ट के सामने एक अनुकूलन योग्य गेटकीपर लगाने जैसा है, जो आपको इसे कैसे एक्सेस और संशोधित किया जाता है, इस पर पूर्ण नियंत्रण देता है।
यह व्यापक मार्गदर्शिका Proxy API को स्पष्ट करेगी। हम इसकी मुख्य अवधारणाओं का पता लगाएंगे, व्यावहारिक उदाहरणों के साथ इसकी विभिन्न क्षमताओं को तोड़ेंगे, और उन्नत उपयोग के मामलों और प्रदर्शन संबंधी विचारों पर चर्चा करेंगे। अंत तक, आप समझेंगे कि प्रॉक्सी आधुनिक फ्रेमवर्क का आधार क्यों हैं और आप क्लीनर, अधिक शक्तिशाली और अधिक रखरखाव योग्य कोड लिखने के लिए उनका लाभ कैसे उठा सकते हैं।
मुख्य अवधारणाओं को समझना: लक्ष्य, हैंडलर और ट्रैप
Proxy API तीन मूलभूत घटकों पर बनाया गया है। प्रॉक्सी में महारत हासिल करने की कुंजी उनकी भूमिकाओं को समझना है।
- लक्ष्य (Target): यह वह मूल ऑब्जेक्ट है जिसे आप लपेटना चाहते हैं। यह किसी भी प्रकार का ऑब्जेक्ट हो सकता है, जिसमें एरे, फ़ंक्शन या यहां तक कि एक और प्रॉक्सी भी शामिल है। प्रॉक्सी इस लक्ष्य को वर्चुअलाइज करता है, और सभी संचालन अंततः (हालांकि जरूरी नहीं) इसे अग्रेषित किए जाते हैं।
- हैंडलर (Handler): यह एक ऑब्जेक्ट है जिसमें प्रॉक्सी के लिए तर्क होता है। यह एक प्लेसहोल्डर ऑब्जेक्ट है जिसकी प्रॉपर्टीज़ फ़ंक्शन होती हैं, जिन्हें 'ट्रैप' के रूप में जाना जाता है। जब प्रॉक्सी पर कोई ऑपरेशन होता है, तो यह हैंडलर पर एक संगत ट्रैप की तलाश करता है।
- ट्रैप (Traps): ये हैंडलर पर वे विधियाँ हैं जो प्रॉपर्टी एक्सेस प्रदान करती हैं। प्रत्येक ट्रैप एक मौलिक ऑब्जेक्ट ऑपरेशन से मेल खाता है। उदाहरण के लिए,
get
ट्रैप प्रॉपर्टी रीडिंग को इंटरसेप्ट करता है, औरset
ट्रैप प्रॉपर्टी राइटिंग को इंटरसेप्ट करता है। यदि हैंडलर पर कोई ट्रैप परिभाषित नहीं है, तो ऑपरेशन को बिना किसी प्रॉक्सी के जैसे ही लक्ष्य पर अग्रेषित किया जाता है।
प्रॉक्सी बनाने का सिंटैक्स सीधा है:
const proxy = new Proxy(target, handler);
आइए एक बहुत ही बुनियादी उदाहरण देखें। हम एक प्रॉक्सी बनाएंगे जो एक खाली हैंडलर का उपयोग करके सभी संचालन को लक्ष्य ऑब्जेक्ट के माध्यम से पारित करेगा।
// मूल ऑब्जेक्ट
const target = {
message: "Hello, World!"
};
// एक खाली हैंडलर। सभी संचालन लक्ष्य पर अग्रेषित किए जाएंगे।
const handler = {};
// प्रॉक्सी ऑब्जेक्ट
const proxy = new Proxy(target, handler);
// प्रॉक्सी पर एक प्रॉपर्टी एक्सेस करना
console.log(proxy.message); // आउटपुट: Hello, World!
// ऑपरेशन को लक्ष्य पर अग्रेषित किया गया था
console.log(target.message); // आउटपुट: Hello, World!
// प्रॉक्सी के माध्यम से एक प्रॉपर्टी को संशोधित करना
proxy.anotherMessage = "Hello, Proxy!";
console.log(proxy.anotherMessage); // आउटपुट: Hello, Proxy!
console.log(target.anotherMessage); // आउटपुट: Hello, Proxy!
इस उदाहरण में, प्रॉक्सी मूल ऑब्जेक्ट की तरह ही व्यवहार करता है। जब हम हैंडलर में ट्रैप को परिभाषित करना शुरू करते हैं तो वास्तविक शक्ति आती है।
एक प्रॉक्सी का एनाटॉमी: सामान्य ट्रैप की खोज
हैंडलर ऑब्जेक्ट में 13 तक विभिन्न ट्रैप हो सकते हैं, प्रत्येक JavaScript ऑब्जेक्ट की एक मौलिक आंतरिक विधि से मेल खाता है। आइए सबसे आम और उपयोगी पर गौर करें।
प्रॉपर्टी एक्सेस ट्रैप
1. get(target, property, receiver)
यह शायद सबसे अधिक इस्तेमाल किया जाने वाला ट्रैप है। जब प्रॉक्सी की किसी प्रॉपर्टी को पढ़ा जाता है तो यह ट्रिगर होता है।
target
: मूल ऑब्जेक्ट।property
: एक्सेस की जा रही प्रॉपर्टी का नाम।receiver
: प्रॉक्सी स्वयं, या एक ऑब्जेक्ट जो इससे इनहेरिट होता है।
उदाहरण: गैर-मौजूद प्रॉपर्टीज़ के लिए डिफ़ॉल्ट मान।
const user = {
firstName: 'John',
lastName: 'Doe',
age: 30
};
const userHandler = {
get(target, property) {
// यदि प्रॉपर्टी लक्ष्य पर मौजूद है, तो उसे वापस करें।
// अन्यथा, एक डिफ़ॉल्ट संदेश वापस करें।
return property in target ? target[property] : `Property '${property}' does not exist.`;
}
};
const userProxy = new Proxy(user, userHandler);
console.log(userProxy.firstName); // आउटपुट: John
console.log(userProxy.age); // आउटपुट: 30
console.log(userProxy.country); // आउटपुट: Property 'country' does not exist.
2. set(target, property, value, receiver)
जब प्रॉक्सी की किसी प्रॉपर्टी को मान सौंपा जाता है तो set
ट्रैप को कॉल किया जाता है। यह सत्यापन, लॉगिंग या रीड-ओनली ऑब्जेक्ट बनाने के लिए एकदम सही है।
value
: प्रॉपर्टी को सौंपा जा रहा नया मान।- ट्रैप को एक बूलियन लौटाना चाहिए: असाइनमेंट सफल होने पर
true
, और अन्यथाfalse
(जो सख्त मोड मेंTypeError
फेंकेगा)।
उदाहरण: डेटा सत्यापन।
const person = {
name: 'Jane Doe',
age: 25
};
const validationHandler = {
set(target, property, value) {
if (property === 'age') {
if (typeof value !== 'number' || !Number.isInteger(value)) {
throw new TypeError('Age must be an integer.');
}
if (value <= 0) {
throw new RangeError('Age must be a positive number.');
}
}
// यदि सत्यापन पास हो जाता है, तो लक्ष्य ऑब्जेक्ट पर मान सेट करें।
target[property] = value;
// सफलता का संकेत दें।
return true;
}
};
const personProxy = new Proxy(person, validationHandler);
personProxy.age = 30; // यह मान्य है
console.log(personProxy.age); // आउटपुट: 30
try {
personProxy.age = 'thirty'; // TypeError फेंकता है
} catch (e) {
console.error(e.message); // आउटपुट: Age must be an integer.
}
try {
personProxy.age = -5; // RangeError फेंकता है
} catch (e) {
console.error(e.message); // आउटपुट: Age must be a positive number.
}
3. has(target, property)
यह ट्रैप in
ऑपरेटर को इंटरसेप्ट करता है। यह आपको यह नियंत्रित करने की अनुमति देता है कि कौन सी प्रॉपर्टीज़ किसी ऑब्जेक्ट पर मौजूद प्रतीत होती हैं।
उदाहरण: 'निजी' प्रॉपर्टीज़ को छिपाना।
JavaScript में, एक सामान्य कन्वेंशन अंडरस्कोर (_) के साथ निजी प्रॉपर्टीज़ का प्रीफ़िक्स करना है। हम in
ऑपरेटर से इन प्रॉपर्टीज़ को छिपाने के लिए has
ट्रैप का उपयोग कर सकते हैं।
const secretData = {
_apiKey: 'xyz123abc',
publicKey: 'pub456def',
id: 1
};
const hidingHandler = {
has(target, property) {
if (property.startsWith('_')) {
return false; // जैसे कि यह मौजूद नहीं है
}
return property in target;
}
};
const dataProxy = new Proxy(secretData, hidingHandler);
console.log('publicKey' in dataProxy); // आउटपुट: true
console.log('_apiKey' in dataProxy); // आउटपुट: false (भले ही यह लक्ष्य पर हो)
console.log('id' in dataProxy); // आउटपुट: true
नोट: यह केवल in
ऑपरेटर को प्रभावित करता है। dataProxy._apiKey
जैसे प्रत्यक्ष एक्सेस अभी भी काम करेंगे जब तक कि आप एक संगत get
ट्रैप को भी लागू नहीं करते।
4. deleteProperty(target, property)
जब delete
ऑपरेटर का उपयोग करके किसी प्रॉपर्टी को हटाया जाता है तो यह ट्रैप निष्पादित होता है। यह महत्वपूर्ण प्रॉपर्टीज़ के विलोपन को रोकने के लिए उपयोगी है।
ट्रैप को सफल विलोपन के लिए true
या असफल के लिए false
लौटाना चाहिए।
उदाहरण: प्रॉपर्टीज़ के विलोपन को रोकना।
const immutableConfig = {
databaseUrl: 'prod.db.server',
port: 8080
};
const deletionGuardHandler = {
deleteProperty(target, property) {
if (property in target) {
console.warn(`Attempted to delete protected property: '${property}'. Operation denied.`);
return false;
}
return true; // प्रॉपर्टी वैसे भी मौजूद नहीं थी
}
};
const configProxy = new Proxy(immutableConfig, deletionGuardHandler);
delete configProxy.port;
// कंसोल आउटपुट: Attempted to delete protected property: 'port'. Operation denied.
console.log(configProxy.port); // आउटपुट: 8080 (इसे हटाया नहीं गया था)
ऑब्जेक्ट एन्यूमरेशन और डिस्क्रिप्शन ट्रैप
5. ownKeys(target)
यह ट्रैप किसी ऑब्जेक्ट की अपनी प्रॉपर्टीज़ की सूची प्राप्त करने वाले ऑपरेशंस द्वारा ट्रिगर होता है, जैसे Object.keys()
, Object.getOwnPropertyNames()
, Object.getOwnPropertySymbols()
, और Reflect.ownKeys()
।
उदाहरण: कुंजियों को फ़िल्टर करना।
आइए उन्हें पूरी तरह से छिपाने के लिए इसे हमारे पिछले 'निजी' प्रॉपर्टी उदाहरण के साथ जोड़ें।
const secretData = {
_apiKey: 'xyz123abc',
publicKey: 'pub456def',
id: 1
};
const keyHidingHandler = {
has(target, property) {
return !property.startsWith('_') && property in target;
},
ownKeys(target) {
return Reflect.ownKeys(target).filter(key => !key.startsWith('_'));
},
get(target, property, receiver) {
// प्रत्यक्ष एक्सेस को भी रोकें
if (property.startsWith('_')) {
return undefined;
}
return Reflect.get(target, property, receiver);
}
};
const fullProxy = new Proxy(secretData, keyHidingHandler);
console.log(Object.keys(fullProxy)); // आउटपुट: ['publicKey', 'id']
console.log('publicKey' in fullProxy); // आउटपुट: true
console.log('_apiKey' in fullProxy); // आउटपुट: false
console.log(fullProxy._apiKey); // आउटपुट: undefined
ध्यान दें कि हम यहां Reflect
का उपयोग कर रहे हैं। Reflect
ऑब्जेक्ट इंटरसेप्टेबल JavaScript ऑपरेशंस के लिए विधियाँ प्रदान करता है, और इसकी विधियों में प्रॉक्सी ट्रैप के समान नाम और हस्ताक्षर होते हैं। मूल ऑपरेशन को लक्ष्य पर अग्रेषित करने के लिए Reflect
का उपयोग करना एक सर्वोत्तम अभ्यास है, यह सुनिश्चित करते हुए कि डिफ़ॉल्ट व्यवहार सही ढंग से बनाए रखा गया है।
फ़ंक्शन और कंस्ट्रक्टर ट्रैप
प्रॉक्सी केवल सादे ऑब्जेक्ट तक ही सीमित नहीं हैं। जब लक्ष्य एक फ़ंक्शन होता है, तो आप कॉल और कंस्ट्रक्शन को इंटरसेप्ट कर सकते हैं।
6. apply(target, thisArg, argumentsList)
जब किसी फ़ंक्शन के प्रॉक्सी को निष्पादित किया जाता है तो इस ट्रैप को कॉल किया जाता है। यह फ़ंक्शन कॉल को इंटरसेप्ट करता है।
target
: मूल फ़ंक्शन।thisArg
: कॉल के लिएthis
संदर्भ।argumentsList
: फ़ंक्शन को पास किए गए तर्कों की सूची।
उदाहरण: फ़ंक्शन कॉल और उनके तर्कों को लॉग करना।
function sum(a, b) {
return a + b;
}
const loggingHandler = {
apply(target, thisArg, argumentsList) {
console.log(`Calling function '${target.name}' with arguments: ${argumentsList}`);
// सही संदर्भ और तर्कों के साथ मूल फ़ंक्शन निष्पादित करें
const result = Reflect.apply(target, thisArg, argumentsList);
console.log(`Function '${target.name}' returned: ${result}`);
return result;
}
};
const proxiedSum = new Proxy(sum, loggingHandler);
proxiedSum(5, 10);
// कंसोल आउटपुट:
// Calling function 'sum' with arguments: 5,10
// Function 'sum' returned: 15
7. construct(target, argumentsList, newTarget)
यह ट्रैप क्लास या फ़ंक्शन के प्रॉक्सी पर new
ऑपरेटर के उपयोग को इंटरसेप्ट करता है।
उदाहरण: सिंगलटन पैटर्न कार्यान्वयन।
class MyDatabaseConnection {
constructor(url) {
this.url = url;
console.log(`Connecting to ${this.url}...`);
}
}
let instance;
const singletonHandler = {
construct(target, argumentsList) {
if (!instance) {
console.log('Creating new instance.');
instance = Reflect.construct(target, argumentsList);
}
console.log('Returning existing instance.');
return instance;
}
};
const ProxiedConnection = new Proxy(MyDatabaseConnection, singletonHandler);
const conn1 = new ProxiedConnection('db://primary');
// कंसोल आउटपुट:
// Creating new instance.
// Connecting to db://primary...
// Returning existing instance.
const conn2 = new ProxiedConnection('db://secondary'); // URL को अनदेखा किया जाएगा
// कंसोल आउटपुट:
// Returning existing instance.
console.log(conn1 === conn2); // आउटपुट: true
console.log(conn1.url); // आउटपुट: db://primary
console.log(conn2.url); // आउटपुट: db://primary
व्यावहारिक उपयोग के मामले और उन्नत पैटर्न
अब जब हमने व्यक्तिगत ट्रैप को कवर कर लिया है, तो आइए देखें कि वास्तविक दुनिया की समस्याओं को हल करने के लिए उन्हें कैसे जोड़ा जा सकता है।
1. API एब्स्ट्रैक्शन और डेटा ट्रांसफॉर्मेशन
API अक्सर ऐसे प्रारूप में डेटा लौटाते हैं जो आपके एप्लिकेशन के सम्मेलनों से मेल नहीं खाता (जैसे, snake_case
बनाम camelCase
)। एक प्रॉक्सी पारदर्शी रूप से इस रूपांतरण को संभाल सकता है।
function snakeToCamel(s) {
return s.replace(/(_\w)/g, (m) => m[1].toUpperCase());
}
// कल्पना करें कि यह एक API से हमारा कच्चा डेटा है
const apiResponse = {
user_id: 123,
first_name: 'Alice',
last_name: 'Wonderland',
account_status: 'active'
};
const camelCaseHandler = {
get(target, property) {
const camelCaseProperty = snakeToCamel(property);
// जांचें कि क्या camelCase संस्करण सीधे मौजूद है
if (camelCaseProperty in target) {
return target[camelCaseProperty];
}
// मूल प्रॉपर्टी नाम पर वापस जाएं
if (property in target) {
return target[property];
}
return undefined;
}
};
const userModel = new Proxy(apiResponse, camelCaseHandler);
// हम अब camelCase का उपयोग करके प्रॉपर्टीज़ एक्सेस कर सकते हैं, भले ही वे snake_case के रूप में संग्रहीत हों
console.log(userModel.userId); // आउटपुट: 123
console.log(userModel.firstName); // आउटपुट: Alice
console.log(userModel.accountStatus); // आउटपुट: active
2. अवलोकनीय और डेटा बाइंडिंग (आधुनिक फ्रेमवर्क का मूल)
प्रॉक्सी Vue 3 जैसे आधुनिक फ्रेमवर्क में प्रतिक्रियाशीलता प्रणालियों के पीछे इंजन हैं। जब आप किसी प्रॉक्सी किए गए स्टेट ऑब्जेक्ट पर किसी प्रॉपर्टी को बदलते हैं, तो set
ट्रैप का उपयोग UI या एप्लिकेशन के अन्य भागों में अपडेट को ट्रिगर करने के लिए किया जा सकता है।
यहां एक अत्यधिक सरलीकृत उदाहरण दिया गया है:
function createObservable(target, callback) {
const handler = {
set(obj, prop, value) {
const result = Reflect.set(obj, prop, value);
callback(prop, value); // परिवर्तन पर कॉलबैक ट्रिगर करें
return result;
}
};
return new Proxy(target, handler);
}
const state = {
count: 0,
message: 'Hello'
};
function render(prop, value) {
console.log(`CHANGE DETECTED: The property '${prop}' was set to '${value}'. Re-rendering UI...`);
}
const observableState = createObservable(state, render);
observableState.count = 1;
// कंसोल आउटपुट: CHANGE DETECTED: The property 'count' was set to '1'. Re-rendering UI...
observableState.message = 'Goodbye';
// कंसोल आउटपुट: CHANGE DETECTED: The property 'message' was set to 'Goodbye'. Re-rendering UI...
3. नकारात्मक ऐरे इंडेक्स
एक क्लासिक और मजेदार उदाहरण ऐरे व्यवहार का विस्तार करना है जो नकारात्मक इंडेक्स का समर्थन करता है, जहां -1
अंतिम तत्व को संदर्भित करता है, पाइथन जैसी भाषाओं के समान।
function createNegativeArrayProxy(arr) {
const handler = {
get(target, property) {
const index = Number(property);
if (!Number.isNaN(index) && index < 0) {
// नकारात्मक इंडेक्स को अंत से एक सकारात्मक इंडेक्स में बदलें
property = String(target.length + index);
}
return Reflect.get(target, property);
}
};
return new Proxy(arr, handler);
}
const originalArray = ['a', 'b', 'c', 'd', 'e'];
const proxiedArray = createNegativeArrayProxy(originalArray);
console.log(proxiedArray[0]); // आउटपुट: a
console.log(proxiedArray[-1]); // आउटपुट: e
console.log(proxiedArray[-2]); // आउटपुट: d
console.log(proxiedArray.length); // आउटपुट: 5
प्रदर्शन विचार और सर्वोत्तम अभ्यास
जबकि प्रॉक्सी अविश्वसनीय रूप से शक्तिशाली हैं, वे कोई जादुई गोली नहीं हैं। उनके निहितार्थों को समझना महत्वपूर्ण है।
प्रदर्शन ओवरहेड
एक प्रॉक्सी अप्रत्यक्षता की एक परत पेश करती है। प्रॉक्सी किए गए ऑब्जेक्ट पर हर ऑपरेशन को हैंडलर से गुजरना पड़ता है, जो एक सादे ऑब्जेक्ट पर सीधे ऑपरेशन की तुलना में थोड़ी मात्रा में ओवरहेड जोड़ता है। अधिकांश अनुप्रयोगों (जैसे डेटा सत्यापन या फ्रेमवर्क-स्तरीय प्रतिक्रियाशीलता) के लिए, यह ओवरहेड नगण्य है। हालांकि, प्रदर्शन-महत्वपूर्ण कोड में, जैसे कि लाखों आइटम संसाधित करने वाला एक टाइट लूप, यह एक बाधा बन सकता है। यदि प्रदर्शन एक प्राथमिक चिंता का विषय है तो हमेशा बेंचमार्क करें।
प्रॉक्सी इनवेरिएंट्स
एक ट्रैप लक्ष्य ऑब्जेक्ट की प्रकृति के बारे में पूरी तरह से झूठ नहीं बोल सकता है। JavaScript 'इनवेरिएंट्स' नामक नियमों का एक सेट लागू करता है जिसका प्रॉक्सी ट्रैप को पालन करना चाहिए। इनवेरिएंट का उल्लंघन करने पर TypeError
होगा।
उदाहरण के लिए, deleteProperty
ट्रैप के लिए एक इनवेरिएंट यह है कि यह true
(सफलता का संकेत) नहीं लौटा सकता है यदि लक्ष्य ऑब्जेक्ट पर संबंधित प्रॉपर्टी गैर-कॉन्फ़िगर करने योग्य है। यह प्रॉक्सी को उस प्रॉपर्टी को हटाने का दावा करने से रोकता है जिसे हटाया नहीं जा सकता।
const target = {};
Object.defineProperty(target, 'unbreakable', { value: 10, configurable: false });
const handler = {
deleteProperty(target, prop) {
// यह इनवेरिएंट का उल्लंघन करेगा
return true;
}
};
const proxy = new Proxy(target, handler);
try {
delete proxy.unbreakable; // यह एक त्रुटि फेंक देगा
} catch (e) {
console.error(e.message);
// आउटपुट: 'deleteProperty' on proxy: returned true for non-configurable property 'unbreakable'
}
प्रॉक्सी का उपयोग कब करें (और कब न करें)
- इसके लिए अच्छा है: फ्रेमवर्क और लाइब्रेरी बनाना (जैसे, स्टेट मैनेजमेंट, ORM), डिबगिंग और लॉगिंग, मजबूत सत्यापन सिस्टम लागू करना, और अंतर्निहित डेटा संरचनाओं को एब्स्ट्रैक्ट करने वाले शक्तिशाली API बनाना।
- विकल्पों पर विचार करें: प्रदर्शन-महत्वपूर्ण एल्गोरिदम के लिए, सरल ऑब्जेक्ट एक्सटेंशन के लिए जहां एक क्लास या फैक्ट्री फ़ंक्शन पर्याप्त होगा, या जब आपको बहुत पुराने ब्राउज़रों का समर्थन करने की आवश्यकता हो जिनमें ES6 समर्थन न हो।
वोकैबल प्रॉक्सी
उन परिदृश्यों के लिए जहां आपको प्रॉक्सी को 'बंद' करने की आवश्यकता हो सकती है (जैसे, सुरक्षा कारणों या मेमोरी प्रबंधन के लिए), JavaScript Proxy.revocable()
प्रदान करता है। यह प्रॉक्सी और एक revoke
फ़ंक्शन दोनों वाले ऑब्जेक्ट लौटाता है।
const target = { data: 'sensitive' };
const handler = {};
const { proxy, revoke } = Proxy.revocable(target, handler);
console.log(proxy.data); // आउटपुट: sensitive
// अब, हम प्रॉक्सी की पहुंच रद्द करते हैं
revoke();
try {
console.log(proxy.data); // यह एक त्रुटि फेंक देगा
} catch (e) {
console.error(e.message);
// आउटपुट: Cannot perform 'get' on a proxy that has been revoked
}
प्रॉक्सी बनाम अन्य मेटाप्रोग्रामिंग तकनीकें
प्रॉक्सी से पहले, डेवलपर्स ने समान लक्ष्य प्राप्त करने के लिए अन्य तरीकों का इस्तेमाल किया। प्रॉक्सी की तुलना कैसे की जाती है, इसे समझना उपयोगी है।
Object.defineProperty()
Object.defineProperty()
विशिष्ट प्रॉपर्टीज़ के लिए गेटर्स और सेटर्स को परिभाषित करके सीधे ऑब्जेक्ट को संशोधित करता है। दूसरी ओर, प्रॉक्सी मूल ऑब्जेक्ट को बिल्कुल भी संशोधित नहीं करते हैं; वे इसे लपेटते हैं।
- स्कोप: `defineProperty` प्रति-प्रॉपर्टी आधार पर काम करता है। आप जिस हर प्रॉपर्टी को देखना चाहते हैं, उसके लिए आपको एक गेटर/सेटर परिभाषित करना होगा। एक प्रॉक्सी के
get
औरset
ट्रैप वैश्विक होते हैं, जो बाद में जोड़ी गई नई प्रॉपर्टीज़ सहित किसी भी प्रॉपर्टी पर ऑपरेशंस को पकड़ते हैं। - क्षमताएं: प्रॉक्सी ऑपरेशंस की एक विस्तृत श्रृंखला को इंटरसेप्ट कर सकते हैं, जैसे
deleteProperty
,in
ऑपरेटर, और फ़ंक्शन कॉल, जिसे `defineProperty` नहीं कर सकता।
निष्कर्ष: वर्चुअलाइजेशन की शक्ति
JavaScript Proxy API सिर्फ एक चतुर सुविधा से कहीं अधिक है; यह इस बात का एक मौलिक बदलाव है कि हम ऑब्जेक्ट को कैसे डिजाइन और इंटरैक्ट कर सकते हैं। मौलिक ऑपरेशंस को इंटरसेप्ट और कस्टमाइज़ करने की अनुमति देकर, प्रॉक्सी शक्तिशाली पैटर्न्स की दुनिया के द्वार खोलते हैं: निर्बाध डेटा सत्यापन और परिवर्तन से लेकर उन प्रतिक्रियाशील प्रणालियों तक जो आधुनिक उपयोगकर्ता इंटरफेस को शक्ति प्रदान करती हैं।
हालांकि उनके पास थोड़ा प्रदर्शन लागत और पालन करने के लिए नियमों का एक सेट है, उनकी स्वच्छ, अलग-थलग और शक्तिशाली एब्स्ट्रैक्शन बनाने की क्षमता बेजोड़ है। ऑब्जेक्ट को वर्चुअलाइज करके, आप ऐसे सिस्टम बना सकते हैं जो अधिक मजबूत, रखरखाव योग्य और अभिव्यंजक हों। अगली बार जब आप डेटा प्रबंधन, सत्यापन, या अवलोकनीयता से जुड़े एक जटिल चुनौती का सामना करें, तो विचार करें कि क्या एक प्रॉक्सी उस काम के लिए सही उपकरण है। यह सिर्फ आपके टूलकिट में सबसे सुरुचिपूर्ण समाधान हो सकता है।