जावास्क्रिप्ट में रिफ्लेक्ट ऑब्जेक्ट क्या करता है?


87

मैंने Reflectजावास्क्रिप्ट में ऑब्जेक्ट के लिए कुछ समय पहले MDN पर एक खाली स्टब देखा था, लेकिन मैं अपने जीवन के लिए Google पर कुछ भी नहीं खोज सकता। आज मुझे यह http://people.mozilla.org/~jorendorff/es6-draft.html#sec-reflect-object मिला और यह प्रॉक्सी ऑब्जेक्ट के अलावा दायरे और लोडर कार्यक्षमता के समान लगता है।

मूल रूप से, मुझे नहीं पता कि क्या यह पृष्ठ मुझे मिला है जो केवल यह बताता है कि रिफ्लेक्ट को कैसे लागू किया जाए या यदि मैं सिर्फ इसके शब्दों को समझ नहीं पा रहा हूं। क्या कोई मुझे आमतौर पर समझा सकता है कि क्या Reflectकरें?

उदाहरण के लिए, मैंने पाया पृष्ठ पर कहा गया है कि कॉलिंग Reflect.apply ( target, thisArgument, argumentsList ) "[कॉल [] कॉल करने का परिणाम लौटाएगी। इस तर्क और तर्क के साथ लक्ष्य की आंतरिक विधि।" लेकिन यह कैसे सिर्फ फोन करने से अलग है target.apply(thisArgument, argumentsList)?

अपडेट करें:

@Blue की बदौलत, मुझे यह पेज विकी http://wiki.ecmascript.org/doku.php?id=harmony:reflect_api&s=reflect पर मिला, जो कि मेरे ज्ञान में सबसे अच्छा है, जो कहता है कि प्रतिबिंबित सभी के विधि संस्करण प्रदान करता है भविष्यवाणियों को आसान बनाने के लिए कार्यवाही द्वारा फंसे जा सकते हैं। लेकिन यह मेरे लिए थोड़ा अजीब लगता है क्योंकि मैं नहीं देखता कि यह पूरी तरह से कैसे आवश्यक है। लेकिन यह उस से थोड़ा अधिक करने के लिए लगता है, विशेष रूप से बराबर जो कहता है double-liftingलेकिन वह पुराने प्रॉक्सी युक्ति की ओर इशारा करता है /


1
युक्ति कहती है, "प्रतिबिंबित वस्तु एक सामान्य वस्तु है।", मेरी समझ Reflectमें सिर्फ वस्तुओं Realmऔर Loaderवस्तुओं के लिए एक कंटेनर है , लेकिन मुझे नहीं पता कि बाद वाले क्या करते हैं।
सिमोनजैक

धन्यवाद :), मुझे लगता है कि मैं जिस पेज से जुड़ा हुआ हूं उससे लगता है (न जाने कितना वैध है) कि प्रत्येक दायरे का अपना "जावा स्क्रिप्ट का संदर्भ" है और एक लोडर परिलक्षित होता है जैसे मॉड्यूल या कुछ और, परावर्तन के बीच समानता के आधार पर कुछ और प्रॉक्सी और तथ्य यह है कि कार्यक्षमता में निर्मित "ओवरलोड" का प्रॉक्सी प्रकार Reflect.Loaderऔर Reflect.Realmओवरलोडिंग मॉड्यूल कार्यक्षमता के साथ कुछ हो सकता है?
जिम जोन्स

1
: ऐसा लग रहा है स्थिर तरीकों के साथ एक 'स्थिर वर्ग' (JSON) की तरह है isExtensible, ownKeysआदि में ES 6 वास्तविक वर्गों के साथ, यह एक वर्ग के बारे में अधिक जानने के लिए उपयोगी है ( targetमें 16.1.2 मुझे लगता है कि)।
रुडी

क्या आपने github.com/tvcutsem/harmony-reflect/wiki देखा है ?
kangax 17

जवाबों:


129

अद्यतन २०१५: जैसा कि ' वें उत्तर में बताया गया है , अब ईएस ६ (ईसीएमएस्क्रिप्ट २०१५) को अंतिम रूप दे दिया गया है, अधिक उपयुक्त दस्तावेज अब उपलब्ध है:


मूल उत्तर (ऐतिहासिक) समझ और अतिरिक्त उदाहरणों के लिए :

Reflection proposalके लिए आगे बढ़ा दिया है ड्राफ्ट ECMAScript 6 विशिष्टता । यह दस्तावेज़ वर्तमान में Reflect-object के तरीकों की रूपरेखा देता है और केवल -object के बारे में निम्नलिखित Reflectबताता है:

रिफ्लेक्ट ऑब्जेक्ट एक साधारण वस्तु है।

[[प्रोटोटाइप]] रिफ्लेक्ट ऑब्जेक्ट का आंतरिक स्लॉट मानक निर्मित वस्तु प्रोटोटाइप ऑब्जेक्ट (१ ९ .१.३) है।

रिफ्लेक्ट ऑब्जेक्ट एक फ़ंक्शन ऑब्जेक्ट नहीं है। इसका [[निर्माण]] आंतरिक तरीका नहीं है; नए ऑपरेटर के साथ एक निर्माता के रूप में रिफ्लेक्ट ऑब्जेक्ट का उपयोग करना संभव नहीं है । रिफ्लेक्ट ऑब्जेक्ट में एक [[कॉल]] आंतरिक विधि भी नहीं होती है; फ़ंक्शन के रूप में रिफ्लेक्ट ऑब्जेक्ट को इनवोक करना संभव नहीं है।

हालांकि, ईएस हार्मनी में इसके उद्देश्य के बारे में एक संक्षिप्त व्याख्या है :

"@Reflect" मॉड्यूल कई उद्देश्यों को पूरा करता है:
  • अब जब हमारे पास मॉड्यूल है, तो एक "@reflect" मॉड्यूल ऑब्जेक्ट पर पहले से परिभाषित कई प्रतिबिंब तरीकों के लिए एक अधिक प्राकृतिक स्थान है। बैकवर्ड-संगतता उद्देश्यों के लिए, यह संभावना नहीं है कि ऑब्जेक्ट पर स्थिर तरीके गायब हो जाएंगे। हालाँकि, नए तरीकों को ऑब्जेक्ट कंस्ट्रक्टर के बजाय "@reflect" मॉड्यूल में जोड़ा जाना चाहिए।
  • प्रॉक्सी के लिए एक प्राकृतिक घर, वैश्विक प्रॉक्सी बाइंडिंग की आवश्यकता को टालता है।
  • इस मॉड्यूल के अधिकांश तरीके प्रॉक्सी ट्रैप पर वन-टू-वन मैप करते हैं। प्रॉक्सी संचालकों को सुविधाजनक तरीके से संचालन के लिए इन विधियों की आवश्यकता होती है, जैसा कि नीचे दिखाया गया है।



तो, Reflectऑब्जेक्ट कई उपयोगिता फ़ंक्शंस प्रदान करता है, जिनमें से कई वैश्विक ऑब्जेक्ट पर परिभाषित ES5 विधियों के साथ ओवरलैप करने के लिए दिखाई देते हैं।

हालाँकि, यह वास्तव में स्पष्ट नहीं करता है कि मौजूदा समस्याएँ क्या हल करना चाहती हैं या क्या कार्यक्षमता जोड़ी जाती है। मुझे संदेह था कि यह शर्मनाक हो सकता है और वास्तव में, उपरोक्त सद्भाव-कल्पना लिंक 'इन तरीकों के गैर-मानक, अनुमानित कार्यान्वयन' के लिए हैं

उस कोड की जांच करना, इसके उपयोग के बारे में (आगे) विचार दे सकता है, लेकिन शुक्र है कि विकी भी है जो कई कारणों से रेखांकित करता है कि रिफ्लेक्ट ऑब्जेक्ट क्यों उपयोगी है :
(मैंने भविष्य के संदर्भ के लिए निम्न पाठ की प्रतिलिपि बनाई है (और स्वरूपित)। स्रोत के रूप में वे केवल उदाहरण हैं जो मुझे मिल सकते हैं। इसके अलावा, वे समझ में आते हैं, पहले से ही एक अच्छी व्याख्या है और प्रश्न के applyउदाहरण को स्पर्श करें ।)


अधिक उपयोगी रिटर्न मान

कई ऑपरेशन ReflectES5 संचालन के समान हैं Object, जैसे कि Reflect.getOwnPropertyDescriptorऔर Reflect.defineProperty। हालांकि, जब संपत्ति को सफलतापूर्वक परिभाषित किया गया था, तब तक Object.defineProperty(obj, name, desc)या तो वापस आ जाएगा obj, या TypeErrorअन्यथा फेंक दें , Reflect.defineProperty(obj, name, desc)केवल एक बूलियन वापस करने के लिए निर्दिष्ट किया जाता है जो इंगित करता है कि संपत्ति सफलतापूर्वक परिभाषित की गई थी या नहीं। यह आपको इस कोड को रिफलेक्टर करने की अनुमति देता है:

try {
  Object.defineProperty(obj, name, desc);
  // property defined successfully
} catch (e) {
  // possible failure (and might accidentally catch the wrong exception)
}

इसके लिए:

if (Reflect.defineProperty(obj, name, desc)) {
  // success
} else {
  // failure
}

अन्य तरीके जो ऐसी बूलियन सफलता की स्थिति लौटाते हैं Reflect.set(एक संपत्ति को अद्यतन करने के लिए), Reflect.deleteProperty(एक संपत्ति को हटाने के लिए), Reflect.preventExtensions(एक वस्तु को गैर-एक्स्टेंसिबल बनाने के लिए) और Reflect.setPrototypeOf(एक वस्तु के प्रोटोटाइप लिंक को अपडेट करने के लिए)।


प्रथम श्रेणी के संचालन

ईएस 5 में, यह पता लगाने का तरीका कि क्या एक वस्तु objको परिभाषित करना है या एक निश्चित संपत्ति का नाम लिखना है (name in obj)। इसी तरह, एक संपत्ति को हटाने के लिए, एक का उपयोग करता है delete obj[name]। जबकि समर्पित सिंटैक्स अच्छा और छोटा है, इसका मतलब यह भी है कि जब आप ऑपरेशन को प्रथम श्रेणी के मूल्य के रूप में पास करना चाहते हैं, तो आपको इन कार्यों को स्पष्ट रूप से लपेटना होगा।

इसके साथ Reflect, इन कार्यों को आसानी से प्रथम श्रेणी के कार्यों के रूप में परिभाषित किया गया है:
Reflect.has(obj, name)एक कार्यात्मक समतुल्य है (name in obj)और Reflect.deleteProperty(obj, name)एक ऐसा कार्य है जो जैसा करता हैdelete obj[name].


अधिक विश्वसनीय फ़ंक्शन अनुप्रयोग

ES5 में, जब कोई फ़ंक्शन fको एक सरणी के रूप में पैक किए गए तर्कों की एक चर संख्या के साथ एक फ़ंक्शन को कॉल करना चाहता है argsऔर thisमान को बाध्य करता है obj, तो एक व्यक्ति यह लिख सकता है:

f.apply(obj, args)

हालांकि, fएक ऐसी वस्तु हो सकती है जो जानबूझकर या अनजाने में अपनी खुद की applyविधि को परिभाषित करती है । जब आप वास्तव में यह सुनिश्चित करना चाहते हैं कि अंतर्निहित applyफ़ंक्शन कहा जाता है, तो एक आम तौर पर लिखता है:

Function.prototype.apply.call(f, obj, args)

न केवल यह क्रिया है, यह जल्दी से समझना मुश्किल हो जाता है। साथ Reflect, अब आप एक छोटा और आसान समझने के लिए रास्ते में एक विश्वसनीय समारोह कॉल कर सकते हैं:

Reflect.apply(f, obj, args)


परिवर्तनीय-तर्क निर्माता

कल्पना करें कि आप एक तर्क संख्या के साथ एक रचनाकार फ़ंक्शन को कॉल करना चाहते हैं। ईएस 6 में, नए प्रसार सिंटैक्स के लिए धन्यवाद, कोड लिखना संभव होगा:

var obj = new F(...args)

ईएस 5 में, यह लिखना कठिन है, क्योंकि एक फ़ंक्शन को केवल चर संख्या के तर्कों के साथ उपयोग F.applyया F.callकॉल कर सकता है, लेकिन F.constructफ़ंक्शन के लिए newचर संख्या के साथ कोई फ़ंक्शन नहीं है। साथ Reflect, एक अब लिख सकते हैं, ES5 में:

var obj = Reflect.construct(F, args)


प्रॉक्सी जाल के लिए डिफ़ॉल्ट अग्रेषण व्यवहार

Proxyमौजूदा वस्तुओं को लपेटने के लिए वस्तुओं का उपयोग करते समय , एक ऑपरेशन को रोकना, कुछ करना, और फिर "डिफ़ॉल्ट कार्य करना" करना बहुत आम है, जो आमतौर पर लिपटे ऑब्जेक्ट पर इंटरसेप्टेड ऑपरेशन को लागू करने के लिए होता है। उदाहरण के लिए, मान लें कि मैं किसी संपत्ति तक सभी संपत्ति को आसानी से प्रवेश करना चाहता हूं obj:

var loggedObj = new Proxy(obj, {
  get: function(target, name) {
    console.log("get", target, name);
    // now do the default thing
  }
});

Reflectऔर Proxyएपीआई संगठनों ने मिलकर डिजाइन किए गए थे , जिनमें से प्रत्येक के लिए ऐसी है कि Proxyजाल, वहाँ एक इसी विधि से मौजूद है पर Reflectकि "डिफ़ॉल्ट बात करता है"। इसलिए, जब भी आप खुद को एक प्रॉक्सी हैंडलर के अंदर "डिफॉल्ट" चीज करना चाहते हैं, तो सही बात यह है कि Reflectऑब्जेक्ट में संबंधित विधि को हमेशा कॉल करें :

var loggedObj = new Proxy(obj, {
  get: function(target, name) {
    console.log("get", target, name);
    return Reflect.get(target, name);
  }
});

वापसी के प्रकार जाल Reflectके वापसी प्रकार के साथ संगत होने की गारंटी है Proxy


एक्सेसरों के इस-बाइंडिंग को नियंत्रित करें

ES5 में जेनेरिक प्रॉपर्टी एक्सेस या प्रॉपर्टी अपडेट करना काफी आसान है। उदाहरण के लिए:

var name = ... // get property name as a string
obj[name] // generic property lookup
obj[name] = value // generic property update

Reflect.getऔर Reflect.setतरीकों आप एक ही बात करने के लिए है, लेकिन इसके अलावा एक एक अंतिम वैकल्पिक तर्क के रूप में स्वीकार कर पाएगी receiverपैरामीटर है कि आप स्पष्ट रूप से सेट करने की अनुमति देता this-binding जब संपत्ति है कि आप मिल / सेट एक्सेसर है:

var name = ... // get property name as a string
Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper`
Reflect.set(obj, name, value, wrapper)

यह कभी-कभी तब उपयोगी होता है जब आप रैपिंग कर रहे हों objऔर आप चाहते हैं कि एक्सेसर के भीतर कोई भी सेल्फ-अप अपने रैपर के पास दोबारा पहुंच जाए, जैसे कि यदि objइसे परिभाषित किया गया हो:

var obj = {
  get foo() { return this.bar(); },
  bar: function() { ... }
}

कॉलिंग Reflect.get(obj, "foo", wrapper)का कारण होगा this.bar()कॉल पर भेज पाने के लिए wrapper


विरासत से बचें __proto__

कुछ ब्राउज़रों पर, __proto__एक विशेष संपत्ति के रूप में परिभाषित किया गया है जो किसी वस्तु के प्रोटोटाइप तक पहुंच प्रदान करता है। ईएस 5 Object.getPrototypeOf(obj)ने प्रोटोटाइप को क्वेरी करने के लिए एक नई विधि का मानकीकरण किया। Reflect.getPrototypeOf(obj)बिल्कुल वैसा ही करता है, सिवाय इसके कि वस्तु के प्रोटोटाइप को सेट करने के लिए Reflectभी इसी Reflect.setPrototypeOf(obj, newProto)को परिभाषित करता है । यह किसी वस्तु के प्रोटोटाइप को अपडेट करने का नया ES6-compliant तरीका है।
ध्यान दें: setPrototypeOf यह भी मौजूद हैObject (जैसा कि Knu की टिप्पणी द्वारा सही ढंग से बताया गया है )!


EDIT:
साइड-नोट (Q पर टिप्पणियों को संबोधित करते हुए): 'Q: ES6 मॉड्यूल बनाम HTML आयात' पर एक छोटा और सरल उत्तर है जो बताता है Realmsऔर Loaderवस्तुओं को बताता है।

इस लिंक द्वारा एक और स्पष्टीकरण दिया गया है :

एक वास्तविक वस्तु अपने स्वयं के वैश्विक वस्तु, मानक पुस्तकालय की प्रतिलिपि और "आंतरिक" (मानक वस्तुएं जो वैश्विक चर के लिए बाध्य नहीं हैं, जैसे Object.prototype के प्रारंभिक मूल्य) के साथ एक अलग वैश्विक वातावरण की धारणा को सार करती है।

एक्स्टेंसिबल वेब : यह <iframe>DOM के बिना एक ही मूल के गतिशील समकक्ष है ।

हालांकि उल्लेख के लायक: यह सब अभी भी मसौदे में है, यह पत्थर में उत्कीर्ण एक विनिर्देश नहीं है! यह ES6 है, इसलिए ब्राउज़र-संगतता को ध्यान में रखें!

उम्मीद है की यह मदद करेगा!


@Spencer Killen: ठीक है .. क्या यह उत्तर सही दिशा में अपने विचारों को इंगित करें और बताएं कि यह कैसे के बीच अंतर करने के लिए संबंधित था Reflect.applyऔर target.apply? या बाउंटी समाप्त होने से पहले मुझे क्या जोड़ना चाहिए?
गीतालीब

2
setPrototypOf भी मौजूद है Object
क्

1
ध्यान दें कि Reflect.getप्रॉक्सी के लिए डिफ़ॉल्ट कार्यान्वयन के रूप में उपयोग करना अच्छी तरह से काम नहीं करता है यदि आप प्रोटोटाइप गुणों के साथ किसी ऑब्जेक्ट को प्रॉक्सी कर रहे हैं। यह सिर्फ शिकायत करता है कि यह काम नहीं करता है। हालाँकि, यदि आप इसके बजाय Reflect.get(target, property)पास किए बिना उपयोग करते हैं receiver, तो यह काम करता है।
CMCDragonkai

मेरे परीक्षण जहां आप हमेशा प्रॉक्सी के माध्यम से संपत्तियों तक पहुंचते हैं, ऐसी स्थिति में परिणाम होता है जहां targetमूल लक्ष्य है कि प्रॉक्सी लपेटता है, जबकि receiverप्रॉक्सी ही है। लेकिन फिर से यह अलग हो सकता है यदि आप गुणों को अलग तरीके से एक्सेस करने का प्रबंधन करते हैं।
CMCDragonkai

5

डॉक्यूमेंट डॉक्यूमेंट के अनुसार, विकी पर मिला,

http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts

हमें "एकल साधारण वस्तु" के बारे में रेखा मिलती है जिसे वह मसौदे में स्पष्ट करता है। इसकी फ़ंक्शन परिभाषाएँ भी हैं।

विकी विश्वसनीय होना चाहिए क्योंकि आप इमैस्क्रिप्ट वेबसाइट से इसका लिंक पा सकते हैं

http://www.ecmascript.org/dev.php

मुझे Google द्वारा पहला लिंक मिला, लेकिन सीधे विकी को खोजकर इसे प्राप्त करने का कोई सौभाग्य नहीं था।


धन्यवाद, जब आधिकारिक पद्धति में सूचीबद्ध प्रत्येक विधि को सूचीबद्ध करने के लिए उठाए गए कदम बहुत अधिक लगते हैं तो वे मेरे लिंक में समान होते हैं, लेकिन मैं अभी भी यह पता नहीं लगा सकता कि प्रत्येक विधि क्या कहती है, उदाहरण के लिए रिफ्लेक्ट के तहत। लागू चरणों को सूचीबद्ध किया गया है। तैयार करेंForTailCall सार ऑपरेशन करें। 5. कॉल करने का परिणाम लौटाएं [[कॉल]] तर्क के साथ लक्ष्य की आंतरिक विधि इस तर्क और तर्क ------- इसका क्या मतलब है?
जिम जोन्स

इसे देखने से मेरा सबसे अच्छा अनुमान यह है कि यह चरण 4 में चरण पुनरावृत्ति को संदर्भित कर रहा है और चरण 5 प्रोटोटाइप फ़ंक्शन का संदर्भ है। ऐसा लगता है कि सामान्य विचार यह है कि लागू पद्धति को सत्यापित करना है कि इसके लागू होने पर क्या चल सकता है (चरण 1-2), त्रुटि संभाल (चरण 3) और फिर आह्वान करें फ़ंक्शन लागू करें के खिलाफ चलाया जा रहा है (चरण 4-5)। प्रलेखन के माध्यम से स्कैन करने से मेरा सबसे अच्छा अनुमान यह है कि रिफ्लेक्ट मॉड्यूल का बिंदु तब होता है जब आपके कार्य करने की कार्यक्षमता जिसमें किसी वस्तु के आत्मनिरीक्षण की आवश्यकता होती है। कॉल का उपयोग संभवतः इसलिए भी है कि "इसमें [[कॉल]] आंतरिक विधि नहीं है"।
ब्लू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.