लेक्सिकल स्कोप क्या है?


682

लेक्सिकल स्कूपिंग का संक्षिप्त परिचय क्या है?


89
पॉडकास्ट 58 में, जोएल इन सवालों को प्रोत्साहित करता है क्योंकि वह चाहता है कि एसओ उत्तर के लिए जगह बन जाए, भले ही उन्हें अन्य स्थानों पर जवाब दिया गया हो। यह एक वैध प्रश्न है, हालांकि कोई इसे थोड़ा और विनम्र रख सकता है।
राल्फ एम। रेंकेबाक

5
@ वराह मुझे समझ में आ गया है कि यह एक पुराना सवाल है। लेकिन मुझे यकीन है कि 2009 में भी एसओ को उम्मीद थी कि इसे हल करने की दिशा में कुछ बुनियादी प्रयास किए जाएंगे । जैसा कि यह खड़ा है यह बिल्कुल भी प्रयास नहीं दिखाता है । हो सकता है, इसीलिए इसे कई लोगों ने ठुकरा दिया?
पीपी

13
यह संभव है कि प्रश्नकर्ता इस प्रश्न को लिखते समय अंग्रेजी में धाराप्रवाह नहीं है (या नहीं था)
मार्टिन

27
सवाल विनम्र है, वह सिर्फ वही कहता है जो वह चाहता है। आप जवाब देने के लिए स्वतंत्र हैं। यहां पर ओवरसीज पोलिसी की जरूरत नहीं है।
मार्कस सिबेनेचर

25
मुझे लगता है कि ये प्रश्न महान हैं क्योंकि यह SO के लिए सामग्री बनाता है। IMO, जो परवाह करता है कि प्रश्न में प्रयास नहीं है ... उत्तर में बड़ी सामग्री होगी और यही इस संदेश बोर्ड पर मायने रखता है।
Jwan622

जवाबों:


686

मैं उन्हें उदाहरणों के माध्यम से समझता हूं। :)

सी-सिंटैक्स में पहला, लेक्सिकल स्कोप (जिसे स्टैटिक स्कोप भी कहा जाता है ):

void fun()
{
    int x = 5;

    void fun2()
    {
        printf("%d", x);
    }
}

प्रत्येक आंतरिक स्तर अपने बाहरी स्तरों तक पहुँच सकता है।

एक और तरीका है, जिसे Lisp के पहले कार्यान्वयन द्वारा उपयोग किया जाने वाला डायनेमिक स्कोप कहा जाता है , एक C- जैसे सिंटैक्स में फिर से:

void fun()
{
    printf("%d", x);
}

void dummy1()
{
    int x = 5;

    fun();
}

void dummy2()
{
    int x = 10;

    fun();
}

यहाँ funया तो पहुंचा जा सकता है xमें dummy1या dummy2, या किसी भी xहै कि कॉल किसी भी समारोह में funसाथ xउस में घोषित कर दिया।

dummy1();

5 प्रिंट करेगा,

dummy2();

10 प्रिंट करेगा।

पहले एक को स्थिर कहा जाता है क्योंकि इसे संकलन-समय पर घटाया जा सकता है, और दूसरे को गतिशील कहा जाता है क्योंकि बाहरी गुंजाइश गतिशील है और कार्यों की श्रृंखला कॉल पर निर्भर करती है।

मुझे आंख के लिए स्थिर स्कूपिंग आसान लगती है। अधिकांश भाषाएं इस तरह चली गईं, यहां तक ​​कि लिस्प (दोनों सही कर सकते हैं?)। डायनामिक स्कोपिंग सभी प्रकार के संदर्भों को संदर्भित करने के लिए है जैसे कि फ़ंक्शन।

संकलक किसी फ़ंक्शन के बाहरी गतिशील दायरे को कम क्यों नहीं कर सकता है, इसके एक उदाहरण के रूप में, हमारे अंतिम उदाहरण पर विचार करें। अगर हम ऐसा कुछ लिखते हैं:

if(/* some condition */)
    dummy1();
else
    dummy2();

कॉल चेन रन टाइम कंडीशन पर निर्भर करती है। यदि यह सत्य है, तो कॉल श्रृंखला इस प्रकार दिखाई देती है:

dummy1 --> fun()

अगर हालत झूठी है:

dummy2 --> fun()

funदोनों मामलों में बाहरी गुंजाइश फोन करने वाले और कॉल करने वाले के कॉल करने वाले का प्लस है

सिर्फ यह उल्लेख करने के लिए कि सी भाषा नेस्टेड फ़ंक्शन और न ही डायनेमिक स्कोपिंग की अनुमति नहीं देती है।


19
मैं एक बहुत ही आसान ट्यूटोरियल को समझना चाहता हूं जो मैंने अभी पाया है। अरक का उदाहरण अच्छा है, लेकिन किसी ऐसे व्यक्ति के लिए बहुत कम हो सकता है जिसे अधिक उदाहरणों की आवश्यकता होती है (वास्तव में, अन्य भाषाओं के साथ तुलना ..)। जरा देखो तो। यह समझना महत्वपूर्ण है यह , के रूप में उस कीवर्ड हमें नेतृत्व शाब्दिक दायरे को समझने के लिए होगा। howtonode.org/what-is-this
CppLearner

9
यह एक अच्छा जवाब है। लेकिन सवाल का टैग लगा है JavaScript। इसलिए मुझे लगता है कि इसे स्वीकृत उत्तर के रूप में चिह्नित नहीं किया जाना चाहिए। जे एस में विशेष रूप से शाब्दिक गुंजाइश अलग है
Boyang

6
बहुत अच्छा जवाब। धन्यवाद। @ बोयांग मैं असहमत हूं। मैं एक लिस्प कोडर नहीं हूं, लेकिन लिस्प उदाहरण को मददगार पाया, क्योंकि यह गतिशील स्कूपिंग का एक उदाहरण है, जो आपको जेएस में नहीं मिलता है।
दुदिवद

4
शुरू में मुझे लगा कि उदाहरण सी कोड मान्य था और इस बात को लेकर असमंजस था कि क्या सी में डायनामिक स्कूपिंग है? शायद कोड के उदाहरण से पहले अंत में डिस्क्लेमर को स्थानांतरित किया जा सकता है?
यांगशुन तय

2
यह अभी भी एक बहुत ही उपयोगी उत्तर है लेकिन मुझे लगता है कि @Boyang सही है। यह उत्तर 'स्तर' को संदर्भित करता है, जो कि सी के पास ब्लॉक गुंजाइश की रेखाओं के साथ अधिक है। डिफ़ॉल्ट रूप से जावास्क्रिप्ट में ब्लॉक स्तर की गुंजाइश नहीं होती है, इसलिए forलूप के अंदर विशिष्ट समस्या है। जावास्क्रिप्ट के लिए लेक्सिकल स्कोप केवल फ़ंक्शन स्तर पर है जब तक कि ES6 letया constउपयोग नहीं किया जाता है।
icc97

274

चलो सबसे कम संभव परिभाषा का प्रयास करें:

लेक्सिकल स्कोपिंग परिभाषित करता है कि कैसे नेस्टेड फ़ंक्शन में चर नाम हल किए जाते हैं: आंतरिक फ़ंक्शन में पेरेंट फ़ंक्शन का दायरा होता है, भले ही मूल फ़ंक्शन वापस आ गया हो

इसके लिए वहां यही सब है!


21
अंतिम भाग: "यहां तक ​​कि अगर मूल फ़ंक्शन वापस आ गया है" को क्लोजर कहा जाता है।
जुआनमा मेंडेज़

1
लेक्सिकल स्कोपिंग को समझो और सिर्फ एक भावना में बंद करो। धन्यवाद!!
कालकोठरी

63
var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

उपरोक्त कोड "मैं सिर्फ एक स्थानीय हूं" वापस आ जाएगा। यह "मैं एक वैश्विक हूँ" वापस नहीं आऊँगा। क्योंकि फ़ंक्शन फ़ंक () मायने रखता है कि मूल रूप से कहाँ परिभाषित किया गया था जो फ़ंक्शन व्हाटमिसकॉप के दायरे में है।

यह जो कुछ भी कहा जा रहा है उससे परेशान नहीं होगा (वैश्विक गुंजाइश / एक अन्य फ़ंक्शन के भीतर से भी), यही कारण है कि वैश्विक गुंजाइश मूल्य मैं वैश्विक हूं मुद्रित नहीं किया जाएगा।

इसे लेक्सिकल स्कूपिंग कहा जाता है, जहां " कार्यक्षेत्र को उस स्कोप चेन का उपयोग करके निष्पादित किया जाता है जो तब लागू होता था जब उन्हें परिभाषित किया जाता था " - जावास्क्रिप्ट स्क्रिप्ट गाइड के अनुसार।

लेक्सिकल स्कोप एक बहुत ही शक्तिशाली अवधारणा है।

उम्मीद है की यह मदद करेगा..:)


3
यह बहुत अच्छी व्याख्या है अगर आप फंक्शन फेक () {it.scope;} लिखेंगे तो यह एक और चीज जोड़ना चाहता हूं। फिर यह "मैं वैश्विक हूं" इस कीवर्ड का उपयोग करें और आपका दायरा बदल जाएगा
राजेश कुमार भवरसर

41

लेक्सिकल (एकेए स्टेटिक) स्कोपिंग कोड के शाब्दिक कोष के भीतर पूरी तरह से अपनी स्थिति के आधार पर एक चर के दायरे को निर्धारित करने को संदर्भित करता है। एक चर हमेशा अपने शीर्ष-स्तरीय वातावरण को संदर्भित करता है। इसे डायनेमिक स्कोप के संबंध में समझना अच्छा है


41

क्षेत्र उस क्षेत्र को परिभाषित करता है, जहां कार्य, चर और ऐसे उपलब्ध हैं। उदाहरण के लिए एक चर की उपलब्धता को उसके संदर्भ में परिभाषित किया गया है, मान लें कि फ़ंक्शन, फ़ाइल या ऑब्जेक्ट, वे में परिभाषित किए गए हैं। हम आमतौर पर इन स्थानीय चर को कहते हैं।

लेक्सिकल भाग का मतलब है कि आप स्रोत कोड को पढ़ने से गुंजाइश निकाल सकते हैं।

लेक्सिकल स्कोप को स्टैटिक स्कोप के रूप में भी जाना जाता है।

डायनेमिक स्कोप वैश्विक चर को परिभाषित करता है जिसे परिभाषित होने के बाद कहीं से भी कॉल या संदर्भित किया जा सकता है। कभी-कभी उन्हें वैश्विक चर कहा जाता है, भले ही अधिकांश कार्यक्रम भाषाओं में वैश्विक चर शाब्दिक दायरे के होते हैं। इसका मतलब है, यह उस कोड को पढ़ने से लिया जा सकता है जो इस संदर्भ में चर उपलब्ध है। हो सकता है कि किसी को इंस्टीट्यूशन या डेफिनिशन का पता लगाने के लिए किसी का उपयोग करना पड़ता हो या उसमें क्लॉज शामिल हो, लेकिन कोड / कंपाइलर इस जगह के वेरिएबल के बारे में जानता है।

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

गतिशील गुंजाइश के लिए एक दिलचस्प उदाहरण देखने के लिए यहां देखें ।

अधिक जानकारी के लिए यहां और यहां देखें ।

डेल्फी / ऑब्जेक्ट पास्कल में कुछ उदाहरण

डेल्फी में शाब्दिक गुंजाइश है।

unit Main;
uses aUnit;  // makes available all variables in interface section of aUnit

interface

  var aGlobal: string; // global in the scope of all units that use Main;
  type 
    TmyClass = class
      strict private aPrivateVar: Integer; // only known by objects of this class type
                                    // lexical: within class definition, 
                                    // reserved word private   
      public aPublicVar: double;    // known to everyboday that has access to a 
                                    // object of this class type
    end;

implementation

  var aLocalGlobal: string; // known to all functions following 
                            // the definition in this unit    

end.

निकटतम डेल्फी को डायनेमिक स्कोप में मिलता है रजिस्टरक्लास () / गेटक्लास () फ़ंक्शन जोड़ी। इसके उपयोग के लिए यहां देखें ।

मान लीजिए कि एक निश्चित वर्ग को पंजीकृत करने के लिए रजिस्टरक्लास ([TmyClass]) को समय कहा जाता है, कोड को पढ़कर इसकी भविष्यवाणी नहीं की जा सकती है (इसे उपयोगकर्ता द्वारा कॉल बटन क्लिक विधि में कहा जाता है), कोड कॉलिंग गेटक्लास ('TmyClass) को मिलेगा। एक परिणाम या नहीं। रजिस्टरक्लास () को कॉल गेटक्लास () का उपयोग करके इकाई के शाब्दिक दायरे में नहीं होना चाहिए;

डेल्फी 2009 में डायनामिक स्कोप की एक और संभावना गुमनाम तरीके (क्लोजर) हैं, क्योंकि वे अपने कॉलिंग फ़ंक्शन के चर को जानते हैं। यह पुनरावर्ती रूप से कॉलिंग पथ का पालन नहीं करता है और इसलिए पूरी तरह से गतिशील नहीं है।


2
वास्तव में निजी पूरी इकाई में पहुंच योग्य है जहां वर्ग को परिभाषित किया गया है। यही कारण है कि "स्ट्रिक्ट प्राइवेट" को D2006 में पेश किया गया था।
मार्को वैन डे वोर्ट

2
सादे भाषा के लिए +1 (बिना किसी विवरण के जटिल भाषा और उदाहरण दोनों के विपरीत)
पोप्स

36

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

जावास्क्रिप्ट में स्कूपिंग के लिए हमारी पसंद हैं:

  • के रूप में (कोई गुंजाइश समायोजन नहीं है)
  • शाब्दिक var _this = this; function callback(){ console.log(_this); }
  • सीमा callback.bind(this)

यह ध्यान देने योग्य है, मुझे लगता है कि जावास्क्रिप्ट में वास्तव में गतिशील स्कूपिंग नहीं है । कीवर्ड .bindसमायोजित करता है this, और यह करीब है, लेकिन तकनीकी रूप से समान नहीं है।

यहां दोनों दृष्टिकोणों को प्रदर्शित करने वाला एक उदाहरण है। आप हर बार यह निर्णय लेते हैं कि कॉलबैक की गुंजाइश कैसे बनाई जाए, इसलिए यह वादे, इवेंट हैंडलर और बहुत कुछ पर लागू होता है।

शाब्दिक

यहाँ आप Lexical Scopingजावास्क्रिप्ट में कॉलबैक की अवधि क्या हो सकती है :

var downloadManager = {
  initialize: function() {
    var _this = this; // Set up `_this` for lexical access
    $('.downloadLink').on('click', function () {
      _this.startDownload();
    });
  },
  startDownload: function(){
    this.thinking = true;
    // Request the file from the server and bind more callbacks for when it returns success or failure
  }
  //...
};

बाउंड

स्कोप का एक और तरीका है Function.prototype.bind:

var downloadManager = {
  initialize: function() {
    $('.downloadLink').on('click', function () {
      this.startDownload();
    }.bind(this)); // Create a function object bound to `this`
  }
//...

ये विधियाँ, जहाँ तक मुझे पता है, व्यवहारिक रूप से समतुल्य हैं।


इस्तेमाल bindकरने से स्कोप पर असर नहीं पड़ता।
बेन एस्टन

12

लेज़िकल स्कूपिंग: किसी फ़ंक्शन के बाहर घोषित चर वैश्विक चर हैं और जावास्क्रिप्ट प्रोग्राम में हर जगह दिखाई देते हैं। किसी फ़ंक्शन के अंदर घोषित चर में फ़ंक्शन की गुंजाइश होती है और वे केवल उस कोड के लिए दिखाई देते हैं जो उस फ़ंक्शन के अंदर दिखाई देता है।


12

आईबीएम इसे परिभाषित करता है:

किसी प्रोग्राम या सेगमेंट यूनिट का वह भाग जिसमें कोई घोषणा लागू होती है। एक दिनचर्या में घोषित एक पहचानकर्ता उस दिनचर्या के भीतर और सभी नेस्टेड दिनचर्या के भीतर जाना जाता है। यदि कोई नेस्टेड रूटीन समान नाम के साथ कोई आइटम घोषित करता है, तो बाहरी आइटम नेस्टेड रूटीन में उपलब्ध नहीं है।

उदाहरण 1:

function x() {
    /*
    Variable 'a' is only available to function 'x' and function 'y'.
    In other words the area defined by 'x' is the lexical scope of
    variable 'a'
    */
    var a = "I am a";

    function y() {
        console.log( a )
    }
    y();

}
// outputs 'I am a'
x();

उदाहरण 2:

function x() {

    var a = "I am a";

    function y() {
         /*
         If a nested routine declares an item with the same name,
         the outer item is not available in the nested routine.
         */
        var a = 'I am inner a';
        console.log( a )
    }
    y();

}
// outputs 'I am inner a'
x();

8

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

function grandfather() {
    var name = 'Hammad';
    // 'likes' is not accessible here
    function parent() {
        // 'name' is accessible here
        // 'likes' is not accessible here
        function child() {
            // Innermost level of the scope chain
            // 'name' is also accessible here
            var likes = 'Coding';
        }
    }
}

लेक्सिकल स्कोप के बारे में आप जिस चीज पर ध्यान देंगे, वह यह है कि यह आगे काम करती है, मतलब नाम इसके बच्चों के निष्पादन संदर्भों तक पहुँचा जा सकता है। लेकिन यह अपने माता-पिता के लिए पिछड़े काम नहीं करता है, जिसका अर्थ है कि चर likesको उसके माता-पिता द्वारा एक्सेस नहीं किया जा सकता है।

यह हमें यह भी बताता है कि विभिन्न निष्पादन संदर्भों में समान नाम वाले चर निष्पादन स्टैक के ऊपर से नीचे तक पूर्वता प्राप्त करते हैं। एक चर, एक अन्य चर के समान नाम वाले, अंतरतम फ़ंक्शन (निष्पादन स्टैक का सबसे ऊपरी संदर्भ) में उच्च वरीयता होगी।

ध्यान दें कि यह यहाँ से लिया गया है


8

सरल भाषा में, लेक्सिकल स्कोप एक वैरिएबल है जो आपके दायरे के बाहर परिभाषित है या ऊपरी स्कोप आपके स्कोप के अंदर स्वतः उपलब्ध है जिसका मतलब है कि आपको वहां से गुजरने की आवश्यकता नहीं है।

उदाहरण:

let str="JavaScript";

const myFun = () => {
    console.log(str);
}

myFun();

// आउटपुट: जावास्क्रिप्ट


2
एक उदाहरण के साथ मेरे लिए सबसे छोटा और सबसे अच्छा जवाब। जोड़ा जा सकता था कि ES6 'एरो फ़ंक्शंस समस्या को हल करता है bind। उनके साथ, bindअब आवश्यकता नहीं है। इस परिवर्तन के बारे में अधिक जानकारी के लिए stackoverflow.com/a/34361380/11127383
डैनियल डेनिलेकी

4

लेक्सिकल और डायनेमिक स्कूपिंग के आसपास की बातचीत का एक महत्वपूर्ण हिस्सा है जो गायब है: स्कोपेड चर के जीवनकाल का एक स्पष्ट विवरण - या जब चर तक पहुँचा जा सकता है।

डायनेमिक स्कोपिंग केवल बहुत ही शिथिल रूप से "ग्लोबल" स्कूपिंग से मेल खाती है जिस तरीके से हम परंपरागत रूप से इसके बारे में सोचते हैं (कारण मैं दोनों के बीच तुलना लाता हूं कि यह पहले ही उल्लेख किया गया है - और मुझे विशेष रूप से लिंक किए गए लेख की व्याख्या पसंद नहीं है ); यह शायद सबसे अच्छा है कि हम वैश्विक और गतिशील के बीच तुलना नहीं करते हैं - हालांकि माना जाता है, लिंक किए गए लेख के अनुसार, "... [[] यह वैश्विक रूप से स्कूप किए गए चर के विकल्प के रूप में उपयोगी है।"

तो, सादे अंग्रेजी में, दो स्कूपिंग तंत्रों के बीच महत्वपूर्ण अंतर क्या है?

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

हालाँकि - जैसा कि यह ओपी का फोकस नहीं है - डायनेमिक स्कोपिंग पर बहुत अधिक ध्यान नहीं गया है और इसे प्राप्त किए गए ध्यान का मतलब है कि इसे शायद थोड़ा और अधिक की आवश्यकता है (यह अन्य उत्तरों की आलोचना नहीं है, बल्कि "ओह" उस जवाब से हमें लगा कि काश "थोड़ा और" होता। तो, यहाँ थोड़ा अधिक है:

डायनामिक स्कोपिंग का अर्थ है कि फ़ंक्शन कॉल के जीवनकाल के दौरान एक चर बड़े कार्यक्रम के लिए सुलभ है - या, जबकि फ़ंक्शन निष्पादित हो रहा है। वास्तव में, विकिपीडिया वास्तव में दोनों के बीच के अंतर की व्याख्या के साथ एक अच्छा काम करता है । तो यह नहीं करने के लिए के रूप में, यहाँ पाठ है कि गतिशील ढलान का वर्णन है:

... [I] n डायनेमिक स्कोपिंग (या डायनेमिक स्कोप), यदि वैरिएबल नाम का स्कोप एक निश्चित फंक्शन है, तो इसका स्कोप वह समयावधि है, जिसके दौरान फंक्शन चल रहा होता है: फंक्शन चल रहा होता है, वैरिएबल नाम मौजूद होता है , और इसके चर के लिए बाध्य है, लेकिन फ़ंक्शन वापस आने के बाद, चर नाम मौजूद नहीं है।


3

लेक्सिकल स्कोप का अर्थ है कि एक फ़ंक्शन उस संदर्भ में वेरिएबल को देखता है जहां इसे परिभाषित किया गया था, और इसके आसपास के दायरे में नहीं।

यदि आप अधिक विवरण चाहते हैं, तो लिस्प में लेक्सिकल गुंजाइश कैसे काम करती है, इसे देखें । कॉमन क्रिस्प में डायनामिक और लेक्सिकल वैरिएबल में काइल क्रोनिन द्वारा चयनित उत्तर यहां के उत्तरों से बहुत स्पष्ट है।

संयोगवश मैंने केवल एक लिस्प कक्षा में इसके बारे में सीखा, और यह जावास्क्रिप्ट में भी लागू होता है।

मैंने क्रोम के कंसोल में इस कोड को चलाया।

// JavaScript               Equivalent Lisp
var x = 5;                //(setf x 5)
console.debug(x);         //(print x)
function print_x(){       //(defun print-x ()
    console.debug(x);     //    (print x)
}                         //)
(function(){              //(let
    var x = 10;           //    ((x 10))
    console.debug(x);     //    (print x)
    print_x();            //    (print-x)
})();                     //)

आउटपुट:

5
10
5

3

जावास्क्रिप्ट में एक लेक्सिकल स्कोप का मतलब है कि एक फ़ंक्शन के बाहर परिभाषित किया गया एक वैरिएबल डिक्लेरेशन के बाद परिभाषित दूसरे फ़ंक्शन के अंदर पहुंच योग्य हो सकता है। लेकिन विपरीत सत्य नहीं है; किसी फ़ंक्शन के अंदर परिभाषित चर उस फ़ंक्शन के बाहर पहुंच योग्य नहीं होंगे।

जावास्क्रिप्ट में क्लोजर में इस अवधारणा का भारी उपयोग किया जाता है।

मान लीजिए कि हमारे पास नीचे का कोड है।

var x = 2;
var add = function() {
    var y = 1;
    return x + y;
};

अब, जब आप ऐड कहते हैं () -> यह 3 प्रिंट करेगा।

इसलिए, ऐड () फ़ंक्शन ग्लोबल वैरिएबल तक पहुंच रहा है, xजिसे मेथड फंक्शन ऐड से पहले परिभाषित किया गया है। इसे जावास्क्रिप्ट में लेक्सिकल स्कूपिंग के कारण कहा जाता है।


विचार करें कि कोड स्निपेट एक गतिशील रूप से स्कोप भाषा के लिए था। यदि add()फ़ंक्शन जहां दिए गए कोड स्निपेट के तुरंत बाद कहा जाता है, तो यह भी प्रिंट होगा 3. लेक्सिकल स्कूपिंग का मतलब यह नहीं है कि एक फ़ंक्शन स्थानीय संदर्भ के बाहर वैश्विक चर का उपयोग कर सकता है। तो उदाहरण कोड वास्तव में यह दिखाने में मदद नहीं करता है कि लेक्सिकल स्कूपिंग का मतलब क्या है। कोड में लेक्सिकल स्कूपिंग को वास्तव में एक काउंटर उदाहरण या कोड की अन्य संभावित व्याख्याओं के स्पष्टीकरण की आवश्यकता है।
सी पर्किंस

2

निष्पादन क्षेत्र में वर्तमान स्थिति से दिखाई देने वाले पहचानकर्ताओं (जैसे, चर, कार्य, आदि) के लेक्सिकॉन गुंजाइश को संदर्भित करता है।

- global execution context
    - foo
    - bar
    - function1 execution context
        - foo2
        - bar2
        - function2 execution context
            - foo3
            - bar3

foo तथा bar हमेशा उपलब्ध पहचानकर्ताओं के लेक्सिकॉन के भीतर हैं क्योंकि वे वैश्विक हैं।

जब function1निष्पादित किया जाता है, इसके बारे में एक चर्चा में की पहुंच है foo2, bar2, foo, और bar

जब function2निष्पादित किया जाता है, यह एक शब्दकोश की पहुंच है की foo3, bar3, foo2, bar2, foo, औरbar

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

अंत में, यही कारण है कि एक नेस्टेड एक्ज़ीक्यूशन का संदर्भ हमेशा पूर्वजों के एक्जीक्यूशन के संदर्भ तक पहुंच सकता है और इस प्रकार इसकी पहचान अधिक से अधिक पहचानकर्ताओं तक होती है।

देख:

उपरोक्त परिभाषा को सरल बनाने में मदद के लिए @ robr3rd का विशेष धन्यवाद ।


1

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

व्याख्या में तीन बातों का ध्यान रखना शामिल है:

  1. राज्य - अर्थात्, चर और संदर्भित स्मृति स्थान ढेर और स्टैक पर।

  2. उस स्थिति पर संचालन - अर्थात्, आपके कार्यक्रम में कोड की प्रत्येक पंक्ति

  3. वह वातावरण जिसमें एक दिया गया संचालन चलता है - अर्थात्, एक ऑपरेशन पर राज्य का प्रक्षेपण ।

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

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

यह वह ढांचा है जिसमें स्कूपिंग समस्या को परिभाषित किया गया है। अब हमारे विकल्पों के अगले भाग के लिए।

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

यह डायनेमिक स्कोपिंग का सार है , जिसमें कोई भी कोड जिस पर्यावरण में चलता है वह प्रोग्राम की स्थिति के अनुसार उसके निष्पादन संदर्भ से परिभाषित होता है।

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

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


0

प्राचीन प्रश्न है, लेकिन यहाँ इस पर मेरा विचार है।

लेक्सिकल (स्टैटिक) स्कोप से सोर्स कोड में वैरिएबल के स्कोप का पता चलता है

जावास्क्रिप्ट जैसी भाषा में, जहाँ फ़ंक्शंस को पास किया जा सकता है और विविध वस्तुओं के साथ संलग्न और फिर से संलग्न किया जा सकता है, हालांकि आपके पास यह गुंजाइश हो सकती है कि उस समय फ़ंक्शन को कॉल करने पर निर्भर करेगा, लेकिन यह नहीं है। जिस तरह से डायनेमिक स्कोप होगा उस स्कोप को बदलना, और जावास्क्रिप्ट ऐसा नहीं करता, सिवाय संभवतः के साथthis ऑब्जेक्ट ऑब्जेक्ट के ।

बिंदु को स्पष्ट करने के लिए:

var a='apple';

function doit() {
    var a='aardvark';
    return function() {
        alert(a);
    }
}

var test=doit();
test();

उदाहरण में, चर aको विश्व स्तर पर परिभाषित किया गया है, लेकिन doit()फ़ंक्शन में छाया हुआ है । यह फ़ंक्शन एक और फ़ंक्शन देता है, जैसा कि आप देखते हैं, पर निर्भर करता हैa अपने स्वयं के दायरे के बाहर चर है।

यदि आप इसे चलाते हैं, तो आप पाएंगे कि उपयोग किया गया मूल्य है aardvark, appleजो नहीं है , हालांकि यह इसके दायरे में हैtest() फ़ंक्शन के दायरे में है, मूल फ़ंक्शन के शाब्दिक दायरे में नहीं है। यही है, जो स्कोप इस्तेमाल किया गया है वह स्कोप है क्योंकि यह सोर्स कोड में दिखाई देता है, स्कोप नहीं जहां फंक्शन वास्तव में उपयोग किया जाता है।

इस तथ्य के कष्टप्रद परिणाम हो सकते हैं। उदाहरण के लिए, आप यह तय कर सकते हैं कि अपने कार्यों को अलग से व्यवस्थित करना आसान है, और समय आने पर उनका उपयोग करें, जैसे कि ईवेंट हैंडलर में:

var a='apple',b='banana';

function init() {
  var a='aardvark',b='bandicoot';
  document.querySelector('button#a').onclick=function(event) {
    alert(a);
  }
  document.querySelector('button#b').onclick=doB;
}

function doB(event) {
  alert(b);
}

init();
<button id="a">A</button>
<button id="b">B</button>

यह कोड नमूना प्रत्येक में से एक करता है। आप देख सकते हैं कि लेक्सिकल स्कूपिंग के कारण, बटन Aआंतरिक चर का उपयोग करता है, जबकि बटनB नहीं करता है। आपके द्वारा पसंद किए जाने से अधिक आप नेस्टिंग कार्य समाप्त कर सकते हैं।

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


-1

मैं आम तौर पर उदाहरण के द्वारा सीखता हूं, और यहां कुछ है:

const lives = 0;

function catCircus () {
    this.lives = 1;
    const lives = 2;

    const cat1 = {
        lives: 5,
        jumps: () => {
            console.log(this.lives);
        }
    };
    cat1.jumps(); // 1
    console.log(cat1); // { lives: 5, jumps: [Function: jumps] }

    const cat2 = {
        lives: 5,
        jumps: () => {
            console.log(lives);
        }
    };
    cat2.jumps(); // 2
    console.log(cat2); // { lives: 5, jumps: [Function: jumps] }

    const cat3 = {
        lives: 5,
        jumps: () => {
            const lives = 3;
            console.log(lives);
        }
    };
    cat3.jumps(); // 3
    console.log(cat3); // { lives: 5, jumps: [Function: jumps] }

    const cat4 = {
        lives: 5,
        jumps: function () {
            console.log(lives);
        }
    };
    cat4.jumps(); // 2
    console.log(cat4); // { lives: 5, jumps: [Function: jumps] }

    const cat5 = {
        lives: 5,
        jumps: function () {
            var lives = 4;
            console.log(lives);
        }
    };
    cat5.jumps(); // 4
    console.log(cat5); // { lives: 5, jumps: [Function: jumps] }

    const cat6 = {
        lives: 5,
        jumps: function () {
            console.log(this.lives);
        }
    };
    cat6.jumps(); // 5
    console.log(cat6); // { lives: 5, jumps: [Function: jumps] }

    const cat7 = {
        lives: 5,
        jumps: function thrownOutOfWindow () {
            console.log(this.lives);
        }
    };
    cat7.jumps(); // 5
    console.log(cat7); // { lives: 5, jumps: [Function: thrownOutOfWindow] }
}

catCircus();

-1

यह विषय बिल्ट-इन bindफ़ंक्शन के साथ दृढ़ता से संबंधित है और ECMAScript 6 एरो फ़ंक्शंस में पेश किया गया है । यह वास्तव में कष्टप्रद था, क्योंकि हर नए "वर्ग" (फ़ंक्शन वास्तव में) विधि के लिए जिसे हम उपयोग करना चाहते थे, हमें bindगुंजाइश तक पहुंच बनाने के लिए यह करना था।

डिफ़ॉल्ट रूप से जावास्क्रिप्ट thisकार्यों के अपने दायरे को निर्धारित नहीं करता है (यह संदर्भ को सेट नहीं करता है this)। डिफ़ॉल्ट रूप से आपको स्पष्ट रूप से कहना होगा कि आप किस संदर्भ में होना चाहते हैं।

तीर कार्यों स्वचालित रूप से तथाकथित हो जाता है शाब्दिक गुंजाइश (इसके धारक ब्लॉक में चर की परिभाषा के लिए उपयोग किया)। तीर फ़ंक्शन का उपयोग करते समय यह स्वचालित रूप thisसे उस स्थान पर बांधता है जहां तीर फ़ंक्शन को पहले स्थान पर परिभाषित किया गया था, और इस तीर फ़ंक्शन का संदर्भ ब्लॉक है।

नीचे दिए गए सरलतम उदाहरणों पर देखें कि यह व्यवहार में कैसे काम करता है।

एरो फ़ंक्शंस से पहले (डिफ़ॉल्ट रूप से कोई शाब्दिक गुंजाइश नहीं):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const globalScope = programming.getLanguage;
console.log(globalScope()); // Output: undefined

const localScope = programming.getLanguage.bind(programming);
console.log(localScope()); // Output: "JavaScript"

तीर कार्यों के साथ (डिफ़ॉल्ट रूप से शाब्दिक गुंजाइश):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const arrowFunction = () => {
    console.log(programming.getLanguage());
}

arrowFunction(); // Output: "JavaScript"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.