Kodokon kodokon.com

Proxy, Reflect और मेटाप्रोग्रामिंग

Proxy ट्रैप्स के साथ भाषा के मूलभूत ऑपरेशनों को इंटरसेप्ट करें और Reflect के साथ डिफ़ॉल्ट व्यवहार को साफ़-सुथरे तरीके से डेलिगेट करें।

10 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

एक Proxy किसी लक्ष्य वस्तु को लपेटता है और तेरह ट्रैप्स के माध्यम से भाषा के आंतरिक ऑपरेशनों को इंटरसेप्ट करता है: get, set, has (in ऑपरेटर), deleteProperty, ownKeys, apply, construct, इत्यादि। Reflect वस्तु ठीक वही ऑपरेशन फ़ंक्शनों के रूप में उजागर करती है, ट्रैप्स के समान सिग्नेचर के साथ। यह Vue 3 की रिएक्टिविटी, डायनामिक मॉक्स और ORM-शैली API की नींव है।

JAVASCRIPT
const target = { name: "Ada" };

const traced = new Proxy(target, {
  get(obj, prop, receiver) {
    console.log("get " + String(prop));
    return Reflect.get(obj, prop, receiver);
  }
});

traced.name; // get name
Reflect को डेलिगेट किया गया एक न्यूनतम get ट्रैप।

obj[prop] के बजाय Reflect.get(obj, prop, receiver) क्यों? receiver के कारण। यदि प्रॉपर्टी एक एक्सेसर (एक getter) है, तो Reflect.get उसे this के साथ इनवोक करता है जो receiver की ओर इशारा करता है - प्रॉक्सी या उससे विरासत में मिली कोई वस्तु - जबकि obj[prop] this को कच्चे लक्ष्य पर सेट कर देगा। receiver के बिना, this पढ़ने वाले getter तब टूट जाते हैं जैसे ही कोई वस्तु प्रॉक्सी से विरासत में मिलती है।

JAVASCRIPT
const base = {
  get label() {
    return this.name;
  }
};

const proxy = new Proxy(base, {
  get(target, prop, receiver) {
    return Reflect.get(target, prop, receiver);
  }
});

const child = Object.create(proxy);
child.name = "Ada";
console.log(child.label); // "Ada" thanks to the receiver
receiver विरासत में मिले getter में this को संरक्षित रखता है।

गंभीर उपयोग के मामले: लेखन के समय वैधता जाँच (validation), तुरंत गणना की गई वर्चुअल प्रॉपर्टीज़, लॉगिंग, एक्सेस नियंत्रण (has और ownKeys के माध्यम से _ से शुरू होने वाली कुंजियों को छिपाना), या डिफ़ॉल्ट व्यवहार वाली वस्तुएँ। ध्यान दें कि Reflect.set स्ट्रिक्ट मोड में थ्रो करने के बजाय एक बूलियन लौटाता है: आपके ट्रैप को उस रिटर्न मान को प्रसारित करना चाहिए।

JAVASCRIPT
function validated(target) {
  return new Proxy(target, {
    set(obj, prop, value, receiver) {
      if (prop === "age" && !Number.isInteger(value)) {
        throw new TypeError("age must be an integer");
      }
      return Reflect.set(obj, prop, value, receiver);
    }
  });
}

const user = validated({ age: 30 });
user.age = 31;       // ok
// user.age = "old"; // TypeError
लेखन के समय पारदर्शी वैधता जाँच।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. किसी get ट्रैप में, target[prop] के बजाय Reflect.get(target, prop, receiver) को प्राथमिकता क्यों दें?
    • यह तेज़ है क्योंकि Reflect प्रोटोटाइप को दरकिनार कर देता है
    • ताकि getter सही this (receiver) के साथ चलें, न कि कच्चे लक्ष्य के साथ
    • क्योंकि target[prop] ट्रैप को फिर से ट्रिगर करेगा और अनंत पुनरावृत्ति का कारण बनेगा
    • दोनों रूप बिल्कुल समकक्ष हैं
  2. कौन सा ट्रैप "id" in obj अभिव्यक्ति को इंटरसेप्ट करता है?
    • get
    • has
    • ownKeys
    • getOwnPropertyDescriptor
  3. एक get ट्रैप किसी लक्ष्य प्रॉपर्टी के लिए 42 लौटाता है जिसका मान 1 है, जो नॉन-कॉन्फ़िगरेबल और नॉन-राइटेबल घोषित है। क्या होता है?
    • प्रॉक्सी 42 लौटाता है, ट्रैप हमेशा प्राथमिकता लेता है
    • इंजन चुपचाप 1 लौटाता है
    • इंजन इनवैरिएंट उल्लंघन के लिए एक TypeError थ्रो करता है
    • व्यवहार JavaScript इंजन पर निर्भर करता है