यह और स्कोमाचिन एक्मास्क्रिप्ट में

नमस्कार, हेब्र!

पिछले लेख में, हमने ओओपी के सामान्य सिद्धांत की जांच की जैसा कि एक्मास्क्रिप्ट पर लागू किया गया था और जेएस और शास्त्रीय भाषाओं में ओओपी के बीच अंतर के बारे में नौसिखिया डेवलपर्स की लोकप्रिय गिरावट थी।

आज हम दो अन्य समान रूप से महत्वपूर्ण EcmaScript अवधारणाओं के बारे में बात करते हैं, अर्थात्, निष्पादन संदर्भ के साथ इकाई का संबंध (यह कनेक्शन है) और जनरेटिंग संदर्भ ( स्कोपचेन ) के साथ इकाई का संबंध।

तो चलिए शुरू करते है!

यह


प्रश्न के उत्तर में साक्षात्कार में: " इस बारे में हमें और बताएं।" शुरुआती डेवलपर्स, एक नियम के रूप में, बहुत अस्पष्ट उत्तर देते हैं: " यह वस्तु है" बिंदु से पहले "जिसे विधि को कॉल करने के लिए उपयोग किया गया था," " यह वह संदर्भ है जिसमें फ़ंक्शन को बुलाया गया था," आदि ...

वास्तव में, इस अवधारणा के साथ स्थिति, जो एक्मास्क्रिप्ट के लिए केंद्रीय है, कुछ हद तक जटिल है। आइए इसे क्रम में जानें।

मान लें कि हमारे पास एक जावास्क्रिप्ट प्रोग्राम है, जिसमें विश्व स्तर पर घोषित चर हैं; वैश्विक कार्य; स्थानीय फ़ंक्शंस (अन्य कार्यों के अंदर घोषित), फ़ंक्शंस फ़ंक्शंस से लौटे।

const a = 10; const b = 20; const x = { a: 15, b: 25, } function foo(){ return this.a + this.b; } function bar () { const a = 30; return a + b; } function fooBaz(){ function test () { return this.a + this.b; } return test(); } function fooBar() { const a = 40; const b = 50; return function () { return a + b; } } fooBar()(); 

निष्पादन योग्य कोड पर नियंत्रण स्थानांतरित करते समय, निष्पादन संदर्भ में एक प्रविष्टि बनाई जाती है। निष्पादन योग्य कोड - यह कोई भी कोड होता है जिसे हम एक निश्चित समय में निष्पादित करते हैं, यह एक वैश्विक कोड या किसी फ़ंक्शन का कोड हो सकता है।

निष्पादन संदर्भ एक अमूर्तता है जो कोड को टाइप और परिसीमित करता है। इस अमूर्तता के दृष्टिकोण से, कोड को वैश्विक (किसी भी कनेक्टेड स्क्रिप्ट, इनलाइन स्क्रिप्ट) और फ़ंक्शन कोड में विभाजित किया गया है (नेस्टेड फ़ंक्शन का कोड मूल कार्यों के संदर्भ में नहीं है)।

एक तीसरा प्रकार है - एवलकोड। इस लेख में, हम इसकी उपेक्षा करते हैं।

तार्किक रूप से, निष्पादन संदर्भों का समूह एक स्टैक है जो लास्ट-इन-फ़र्स्ट-आउट (लाइफो) के सिद्धांत पर काम करता है। स्टैक के नीचे हमेशा वैश्विक संदर्भ होता है, और शीर्ष वर्तमान निष्पादन योग्य होता है। हर बार जब कोई फ़ंक्शन कहा जाता है, तो उसके संदर्भ में एक प्रविष्टि बनाई जाती है। जब कोई कार्य पूरा होता है, तो उसका संदर्भ समाप्त हो जाता है। स्पेंट संदर्भों को स्टैक से क्रमिक रूप से और रिवर्स ऑर्डर में हटा दिया जाता है।

ऊपर दिए गए कोड पर एक नज़र डालें। हमारे पास वैश्विक कोड में fooBar फ़ंक्शन का कॉल है। FooBar फ़ंक्शन में , हम एक अनाम फ़ंक्शन लौटाते हैं जिसे हम तुरंत कॉल करते हैं। स्टैक के साथ निम्नलिखित परिवर्तन होते हैं: वैश्विक संदर्भ इसमें मिलता है - जब fooBar कहा जाता है , इसका संदर्भ स्टैक पर मिलता है - fooBar संदर्भ समाप्त होता है, एक अनाम फ़ंक्शन लौटाता है और स्टैक से निकाल दिया जाता है - एक अनाम फ़ंक्शन कहा जाता है, इसका फ़ंक्शन स्टैक पर मिलता है - एक अनाम फ़ंक्शन पूरा होता है, एक मान लौटाता है और इसका संदर्भ स्टैक से हटा दिया जाता है - स्क्रिप्ट के अंत में, वैश्विक संदर्भ स्टैक से हटा दिया जाता है।

निष्पादन संदर्भ सशर्त रूप से एक वस्तु के रूप में प्रतिनिधित्व किया जा सकता है। इस वस्तु के गुणों में से एक लेक्सिकल पर्यावरण (एलओ) होगा।

शाब्दिक वातावरण में शामिल हैं:

  • सभी संदर्भ चर घोषणाएँ
  • सभी फ़ंक्शन घोषणाएँ
  • फ़ंक्शन के सभी औपचारिक पैरामीटर (यदि हम कार्यों के संदर्भ में बात कर रहे हैं)

निष्पादन के संदर्भ में प्रवेश करते समय, दुभाषिया संदर्भ को स्कैन करता है। सभी परिवर्तनीय घोषणाएँ और फ़ंक्शन घोषणाएँ संदर्भ की शुरुआत में बढ़ती हैं। चर अपरिभाषित के बराबर बनाए जाते हैं, और फ़ंक्शन उपयोग के लिए पूरी तरह से तैयार हैं।

यह भी निष्पादन संदर्भ की एक संपत्ति है, लेकिन संदर्भ ही नहीं, जैसा कि कुछ नौसिखिए साक्षात्कारकर्ताओं का जवाब है! यह संदर्भ में प्रवेश करते समय परिभाषित किया गया है और संदर्भ के जीवनकाल के अंत तक (जब तक कि संदर्भ स्टैक से हटा नहीं दिया जाता है) अपरिवर्तित रहता है।

वैश्विक निष्पादन संदर्भ में, यह सख्त मोड द्वारा निर्धारित किया जाता है : जब सख्त मोड बंद होता है, तो इसमें एक वैश्विक ऑब्जेक्ट होता है (ब्राउज़र में यह विंडो ऑब्जेक्ट में शीर्ष स्तर पर अनुमानित है), 'उपयोग सख्त' के साथ यह अपरिभाषित है।

कार्यों के संदर्भ में यह - सवाल बहुत अधिक दिलचस्प है!
यह फ़ंक्शन कॉल करने वाले द्वारा निर्धारित किया जाता है और कॉल के सिंटैक्स पर निर्भर करता है। उदाहरण के लिए, जैसा कि हम जानते हैं, ऐसे तरीके हैं जो आपको कॉल करते समय ( फोन , लागू ) और एक विधि है कि आप "तय यह" ( बाँध ) के साथ एक आवरण बनाने के लिए अनुमति देता है मुश्किल पिन करने के लिए अनुमति देते हैं। इन स्थितियों में, हम स्पष्ट रूप से यह बताते हैं और इसकी परिभाषा के बारे में कोई संदेह नहीं हो सकता है।

एक सामान्य फ़ंक्शन कॉल के साथ, स्थिति बहुत अधिक जटिल है!

EcmaScript बिल्ट-इन प्रकारों में से एक, ReferenceType , हमें यह समझने में मदद करेगा कि यह फ़ंक्शन में कैसे चिपका है। यह कार्यान्वयन स्तर पर उपलब्ध आंतरिक प्रकारों में से एक है। तार्किक रूप से, यह दो गुण आधार के साथ एक वस्तु है (एक निश्चित आधार वस्तु के लिए एक संदर्भ जिसके लिए एक संदर्भटाइप वापस आ गया है), संपत्तिनाम (ऑब्जेक्ट के पहचानकर्ता का एक स्ट्रिंग प्रतिनिधित्व जिसके लिए एक संदर्भटाइप वापस किया जाता है)।

ReferenceType सभी वैरिएबल डिक्लेरेशन, फंक्शन डिक्लेरेशन और प्रॉपर्टी रेफ़रेंस के लिए लौटाया जाता है (यह ऐसा मामला है जो इस बात को समझने के दृष्टिकोण से हमें इंटरेस्ट करता है)।

सामान्य रूप से कहे जाने वाले कार्यों के लिए इसे परिभाषित करने का नियम:
यदि ReferenceType फ़ंक्शन सक्रियण कोष्ठक के बाईं ओर है, तो इस ReferenceType का आधार this फ़ंक्शन में रखा गया है। यदि कोई अन्य प्रकार कोष्ठक के बाईं ओर है, तो this या तो एक वैश्विक वस्तु है या undefined (वास्तव में null , लेकिन चूँकि null के पास परिकल्पना के दृष्टिकोण से कोई विशिष्ट मूल्य नहीं है, तो यह एक वैश्विक वस्तु के लिए डाली जाती है, जिसका संदर्भ हो सकता है) सख्त मोड के आधार पर undefined बराबर है)।

आइए एक उदाहरण देखें:

 const x = 0; const obj = { x: 10, foo: function() { return this.x; } } obj.foo();//  10 ..    ReferenceType  base     obj const test = obj.foo;//       test();//  0 ..  test()   .test(),..  base    ,       0. 

मुझे लगता है कि परिभाषा की विधि स्पष्ट रूप से चित्रित की गई है। अब कुछ कम स्पष्ट मामलों पर विचार करें।

कार्यात्मक अभिव्यक्तियाँ


आइए एक दूसरे के लिए हमारे संदर्भ टाइप पर वापस जाएं। इस प्रकार में एक बिल्ट-इन गेटवैल्यू विधि है जो रेफरेंस टाइप के माध्यम से प्राप्त वस्तु का सही प्रकार लौटाती है। अभिव्यक्ति क्षेत्र में, GetValue हमेशा आग लगाता है।

एक उदाहरण:

 (function (){ return this;// this     undefined    strict mode })() 

यह इस तथ्य के कारण है कि गेटवैल्यू हमेशा अभिव्यक्ति क्षेत्र में ट्रिगर होता है। GetValue एक फ़ंक्शन प्रकार देता है, और सक्रियण कोष्ठक के बाईं ओर एक संदर्भप्रकार नहीं है। इसे निर्धारित करने के लिए हमारे नियम को याद करें : यदि कोई अन्य प्रकार कोष्ठक के बाईं ओर है, तो एक वैश्विक वस्तु को this या undefined (वास्तव में null में रखा जाता है, लेकिन चूंकि शून्य का पारिस्थितिकी के दृष्टिकोण से कोई निश्चित मूल्य नहीं है, तो यह एक वैश्विक वस्तु में परिवर्तित हो जाता है। (कड़ी मोड के आधार पर लिंक अपरिभाषित के बराबर हो सकता है)

अभिव्यक्ति क्षेत्र हैं: असाइनमेंट (=), ऑपरेटर || या अन्य लॉजिकल ऑपरेटर, टर्नरी ऑपरेटर, एरे इनिशियलाइज़र, अल्पविराम से अलग सूची।

 const x = 0; const obj = { x: 10, foo: function() { return this.x; } } obj.foo(); //        //  ? (obj.foo)(); // ,    , GetValue   // ? (obj.foo = obj.foo)(); //        GetValue,     Fuction,   ReferenceType,   0   (   this) //  ||    ,    ..? (obj.foo || obj.foo)();// 0    ,     //  [obj.foo][0]();// 0    ,     // .. 

नामित कार्यात्मक अभिव्यक्तियों में पहचान की स्थिति। यहां तक ​​कि इस वैश्विक वस्तु या undefined लिए एक पुनरावर्ती कॉल के साथ

इस नेस्टेड फ़ंक्शन को पैरेंट में कहा जाता है


इसके अलावा एक महत्वपूर्ण स्थिति!

 const x = 0; function foo() { function bar(){ return this.x; } return bar(); } const obj = {x:10}; obj.test = foo; obj.test();// undefined 

ऐसा इसलिए है क्योंकि कॉल bar() LE_foo.bar के कॉल के बराबर है, और लेक्सिकल वातावरण की वस्तु इस के रूप में अपरिभाषित रखती है।

कंस्ट्रक्टर कार्य करता है


जैसा कि मैंने ऊपर लिखा है:
यह फ़ंक्शन कॉल करने वाले द्वारा निर्धारित किया जाता है और कॉल के सिंटैक्स पर निर्भर करता है।

हम नए कीवर्ड का उपयोग करके निर्माण कार्यों को लागू करते हैं। फ़ंक्शन सक्रियण की इस पद्धति की ख़ासियत यह है कि आंतरिक फ़ंक्शन विधि [[निर्माण]] को कहा जाता है, जो कुछ संचालन करता है (डिजाइनरों द्वारा निकाय बनाने की व्यवस्था OOP पर दूसरे या तीसरे लेख में चर्चा की जाएगी!) और आंतरिक ([कॉल]] विधि को कॉल करता है , जो नीचे डालता है! कंस्ट्रक्टर फ़ंक्शन के इस बनाए गए इंस्टेंस में।

स्कोप चेन


स्कोप चेन भी इस तरह से निष्पादन के संदर्भ की एक संपत्ति है। यह वर्तमान संदर्भ और सभी उत्पन्न संदर्भों के शाब्दिक वातावरण की वस्तुओं की एक सूची है। यह इस श्रृंखला में है कि पहचानकर्ता नामों को हल करते समय चर की खोज होती है।

नोट: यह एक फ़ंक्शन को निष्पादन संदर्भ के साथ जोड़ता है, और स्कोचचिन बाल संदर्भों के साथ।

विनिर्देशन बताता है कि स्कोपचेन एक सरणी है:

  SC = [LO, LO1, LO2,..., LOglobal]; 

हालांकि, जेएस जैसे कुछ कार्यान्वयन में, स्कोप श्रृंखला को लिंक्ड सूची के माध्यम से लागू किया जाता है।

स्कोपचिन को बेहतर ढंग से समझने के लिए, हम कार्यों के जीवन चक्र पर चर्चा करेंगे। इसे सृजन चरण और निष्पादन चरण में विभाजित किया गया है।

जब कोई फ़ंक्शन बनाया जाता है, तो उसे आंतरिक [[SCOPE]] संपत्ति सौंपी जाती है।
[[स्कोप]] में , उच्च (उत्पन्न) संदर्भों के शाब्दिक वातावरण की वस्तुओं की एक श्रेणीबद्ध श्रृंखला दर्ज की गई है। यह संपत्ति अपरिवर्तित बनी हुई है जब तक कि कचरा कलेक्टर द्वारा फ़ंक्शन को नष्ट नहीं किया जाता है।

ध्यान दो! [[स्कोप]] , स्कोपचैइन के विपरीत, फ़ंक्शन का एक गुण है, न कि इसका संदर्भ।

जब किसी फ़ंक्शन को बुलाया जाता है, तो इसका निष्पादन संदर्भ आरंभिक और भरा होता है। संदर्भ को स्कोपचैइन = एलओ (फ़ंक्शन के ही) + [[स्कोप]] (एलओई के पदानुक्रमित श्रृंखला को प्रभावित करने वाले संदर्भों) के साथ चिपका दिया गया है।

पहचानकर्ता के नाम का संकल्प - स्कोपचिन श्रृंखला में एलओ ऑब्जेक्ट्स का क्रमिक मतदान बाएं से दाएं। आउटपुट एक ReferenceType है जिसका आधार गुण LO ऑब्जेक्ट के लिए इंगित करता है जिसमें पहचानकर्ता पाया गया था, और PropertyName पहचानकर्ता नाम का एक स्ट्रिंग प्रतिनिधित्व होगा।

यह कैसे हुड के तहत बंद करने की व्यवस्था है! एक बंद अनिवार्य रूप से सभी चरों के लिए स्कोपचिन में खोज का परिणाम है, जिनके पहचानकर्ता फ़ंक्शन में मौजूद हैं।

 const x = 10; function foo () { return x; } (function (){ const x = 20; foo();// 10 ..     <b><i>[[SCOPE]]</i></b> foo          })() 

निम्न उदाहरण जीवन चक्र [[SCOPE]] को दर्शाता है।

 function foo () { const x = 10; const y = 20; return function () { return [x,y]; } } const x = 30; const bar = foo();//   ,   foo    bar();// [10,20] .. [[SCOPE]]    foo          

एक महत्वपूर्ण अपवाद कंस्ट्रक्टर फ़ंक्शन है । इस प्रकार के फ़ंक्शन के लिए, [[SCOPE]] हमेशा एक वैश्विक वस्तु की ओर इशारा करता है।

इसके अलावा, यह मत भूलो कि यदि स्कोपचैन श्रृंखला के लिंक में से कोई एक प्रोटोटाइप है, तो प्रोटोटाइप में भी खोज की जाएगी।

निष्कर्ष


हम प्रमुख विचारों को सैद्धांतिक रूप से सामने रखेंगे:

  • यह निष्पादन संदर्भ के साथ इकाई का संबंध है
  • स्कोपचेन सभी स्पैनिंग संदर्भों के साथ एक इकाई का संबंध है
  • यह और स्कोपचेन निष्पादन संदर्भ गुण हैं
  • यह फ़ंक्शन कॉलर द्वारा निर्धारित किया जाता है और कॉल के सिंटैक्स पर निर्भर करता है
  • स्कोपचेन वर्तमान संदर्भ + [[स्कोप]] का शाब्दिक वातावरण है
  • [[स्कोप]] - यह स्वयं फंक्शन की एक संपत्ति है, जिसमें कॉन्टेक्ट्स पैदा करने के शाब्दिक वातावरण की एक श्रेणीबद्ध श्रृंखला होती है।

आशा है कि लेख उपयोगी था। भविष्य के लेख तक, दोस्तों!

Source: https://habr.com/ru/post/hi468943/


All Articles