लेक्सिकल स्कूपिंग का संक्षिप्त परिचय क्या है?
लेक्सिकल स्कूपिंग का संक्षिप्त परिचय क्या है?
जवाबों:
मैं उन्हें उदाहरणों के माध्यम से समझता हूं। :)
सी-सिंटैक्स में पहला, लेक्सिकल स्कोप (जिसे स्टैटिक स्कोप भी कहा जाता है ):
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
दोनों मामलों में बाहरी गुंजाइश फोन करने वाले और कॉल करने वाले के कॉल करने वाले का प्लस है ।
सिर्फ यह उल्लेख करने के लिए कि सी भाषा नेस्टेड फ़ंक्शन और न ही डायनेमिक स्कोपिंग की अनुमति नहीं देती है।
JavaScript
। इसलिए मुझे लगता है कि इसे स्वीकृत उत्तर के रूप में चिह्नित नहीं किया जाना चाहिए। जे एस में विशेष रूप से शाब्दिक गुंजाइश अलग है
for
लूप के अंदर विशिष्ट समस्या है। जावास्क्रिप्ट के लिए लेक्सिकल स्कोप केवल फ़ंक्शन स्तर पर है जब तक कि ES6 let
या const
उपयोग नहीं किया जाता है।
चलो सबसे कम संभव परिभाषा का प्रयास करें:
लेक्सिकल स्कोपिंग परिभाषित करता है कि कैसे नेस्टेड फ़ंक्शन में चर नाम हल किए जाते हैं: आंतरिक फ़ंक्शन में पेरेंट फ़ंक्शन का दायरा होता है, भले ही मूल फ़ंक्शन वापस आ गया हो ।
इसके लिए वहां यही सब है!
var scope = "I am global";
function whatismyscope(){
var scope = "I am just a local";
function func() {return scope;}
return func;
}
whatismyscope()()
उपरोक्त कोड "मैं सिर्फ एक स्थानीय हूं" वापस आ जाएगा। यह "मैं एक वैश्विक हूँ" वापस नहीं आऊँगा। क्योंकि फ़ंक्शन फ़ंक () मायने रखता है कि मूल रूप से कहाँ परिभाषित किया गया था जो फ़ंक्शन व्हाटमिसकॉप के दायरे में है।
यह जो कुछ भी कहा जा रहा है उससे परेशान नहीं होगा (वैश्विक गुंजाइश / एक अन्य फ़ंक्शन के भीतर से भी), यही कारण है कि वैश्विक गुंजाइश मूल्य मैं वैश्विक हूं मुद्रित नहीं किया जाएगा।
इसे लेक्सिकल स्कूपिंग कहा जाता है, जहां " कार्यक्षेत्र को उस स्कोप चेन का उपयोग करके निष्पादित किया जाता है जो तब लागू होता था जब उन्हें परिभाषित किया जाता था " - जावास्क्रिप्ट स्क्रिप्ट गाइड के अनुसार।
लेक्सिकल स्कोप एक बहुत ही शक्तिशाली अवधारणा है।
उम्मीद है की यह मदद करेगा..:)
लेक्सिकल (एकेए स्टेटिक) स्कोपिंग कोड के शाब्दिक कोष के भीतर पूरी तरह से अपनी स्थिति के आधार पर एक चर के दायरे को निर्धारित करने को संदर्भित करता है। एक चर हमेशा अपने शीर्ष-स्तरीय वातावरण को संदर्भित करता है। इसे डायनेमिक स्कोप के संबंध में समझना अच्छा है ।
क्षेत्र उस क्षेत्र को परिभाषित करता है, जहां कार्य, चर और ऐसे उपलब्ध हैं। उदाहरण के लिए एक चर की उपलब्धता को उसके संदर्भ में परिभाषित किया गया है, मान लें कि फ़ंक्शन, फ़ाइल या ऑब्जेक्ट, वे में परिभाषित किए गए हैं। हम आमतौर पर इन स्थानीय चर को कहते हैं।
लेक्सिकल भाग का मतलब है कि आप स्रोत कोड को पढ़ने से गुंजाइश निकाल सकते हैं।
लेक्सिकल स्कोप को स्टैटिक स्कोप के रूप में भी जाना जाता है।
डायनेमिक स्कोप वैश्विक चर को परिभाषित करता है जिसे परिभाषित होने के बाद कहीं से भी कॉल या संदर्भित किया जा सकता है। कभी-कभी उन्हें वैश्विक चर कहा जाता है, भले ही अधिकांश कार्यक्रम भाषाओं में वैश्विक चर शाब्दिक दायरे के होते हैं। इसका मतलब है, यह उस कोड को पढ़ने से लिया जा सकता है जो इस संदर्भ में चर उपलब्ध है। हो सकता है कि किसी को इंस्टीट्यूशन या डेफिनिशन का पता लगाने के लिए किसी का उपयोग करना पड़ता हो या उसमें क्लॉज शामिल हो, लेकिन कोड / कंपाइलर इस जगह के वेरिएबल के बारे में जानता है।
डायनामिक स्कोपिंग में, इसके विपरीत, आप पहले स्थानीय फ़ंक्शन में खोज करते हैं, फिर आप उस फ़ंक्शन में खोज करते हैं, जिसे स्थानीय फ़ंक्शन कहा जाता है, फिर आप फ़ंक्शन में उस फ़ंक्शन को खोजते हैं, और इसी तरह, कॉल स्टैक तक। "डायनेमिक" परिवर्तन को संदर्भित करता है, जिसमें कॉल स्टैक हर बार भिन्न हो सकता है जब किसी दिए गए फ़ंक्शन को कॉल किया जाता है, और इसलिए फ़ंक्शन अलग-अलग चर को हिट कर सकता है, जहां यह कहा जाता है। ( यहां देखें )
गतिशील गुंजाइश के लिए एक दिलचस्प उदाहरण देखने के लिए यहां देखें ।
अधिक जानकारी के लिए यहां और यहां देखें ।
डेल्फी / ऑब्जेक्ट पास्कल में कुछ उदाहरण
डेल्फी में शाब्दिक गुंजाइश है।
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 में डायनामिक स्कोप की एक और संभावना गुमनाम तरीके (क्लोजर) हैं, क्योंकि वे अपने कॉलिंग फ़ंक्शन के चर को जानते हैं। यह पुनरावर्ती रूप से कॉलिंग पथ का पालन नहीं करता है और इसलिए पूरी तरह से गतिशील नहीं है।
मुझे @ अरक जैसे लोगों से पूरी तरह से चित्रित, भाषा-अज्ञेयवादी उत्तर पसंद हैं। चूँकि यह सवाल जावास्क्रिप्ट टैग किया गया था , इसलिए मैं इस भाषा के लिए बहुत विशिष्ट कुछ नोट्स में चिप लगाना चाहूंगा।
जावास्क्रिप्ट में स्कूपिंग के लिए हमारी पसंद हैं:
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
करने से स्कोप पर असर नहीं पड़ता।
आईबीएम इसे परिभाषित करता है:
किसी प्रोग्राम या सेगमेंट यूनिट का वह भाग जिसमें कोई घोषणा लागू होती है। एक दिनचर्या में घोषित एक पहचानकर्ता उस दिनचर्या के भीतर और सभी नेस्टेड दिनचर्या के भीतर जाना जाता है। यदि कोई नेस्टेड रूटीन समान नाम के साथ कोई आइटम घोषित करता है, तो बाहरी आइटम नेस्टेड रूटीन में उपलब्ध नहीं है।
उदाहरण 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();
लेक्सिकल स्कोप का अर्थ है कि कार्यों के एक नेस्टेड समूह में, आंतरिक फ़ंक्शंस में चर और अभिभावक के अन्य संसाधनों तक पहुंच होती है । इसका मतलब यह है कि बाल कार्य अपने माता-पिता के निष्पादन के संदर्भ के लिए बाध्य हैं। लेक्सिकल स्कोप को कभी-कभी स्टेटिक स्कोप भी कहा जाता है ।
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
को उसके माता-पिता द्वारा एक्सेस नहीं किया जा सकता है।
यह हमें यह भी बताता है कि विभिन्न निष्पादन संदर्भों में समान नाम वाले चर निष्पादन स्टैक के ऊपर से नीचे तक पूर्वता प्राप्त करते हैं। एक चर, एक अन्य चर के समान नाम वाले, अंतरतम फ़ंक्शन (निष्पादन स्टैक का सबसे ऊपरी संदर्भ) में उच्च वरीयता होगी।
सरल भाषा में, लेक्सिकल स्कोप एक वैरिएबल है जो आपके दायरे के बाहर परिभाषित है या ऊपरी स्कोप आपके स्कोप के अंदर स्वतः उपलब्ध है जिसका मतलब है कि आपको वहां से गुजरने की आवश्यकता नहीं है।
उदाहरण:
let str="JavaScript";
const myFun = () => {
console.log(str);
}
myFun();
// आउटपुट: जावास्क्रिप्ट
bind
। उनके साथ, bind
अब आवश्यकता नहीं है। इस परिवर्तन के बारे में अधिक जानकारी के लिए stackoverflow.com/a/34361380/11127383
लेक्सिकल और डायनेमिक स्कूपिंग के आसपास की बातचीत का एक महत्वपूर्ण हिस्सा है जो गायब है: स्कोपेड चर के जीवनकाल का एक स्पष्ट विवरण - या जब चर तक पहुँचा जा सकता है।
डायनेमिक स्कोपिंग केवल बहुत ही शिथिल रूप से "ग्लोबल" स्कूपिंग से मेल खाती है जिस तरीके से हम परंपरागत रूप से इसके बारे में सोचते हैं (कारण मैं दोनों के बीच तुलना लाता हूं कि यह पहले ही उल्लेख किया गया है - और मुझे विशेष रूप से लिंक किए गए लेख की व्याख्या पसंद नहीं है ); यह शायद सबसे अच्छा है कि हम वैश्विक और गतिशील के बीच तुलना नहीं करते हैं - हालांकि माना जाता है, लिंक किए गए लेख के अनुसार, "... [[] यह वैश्विक रूप से स्कूप किए गए चर के विकल्प के रूप में उपयोगी है।"
तो, सादे अंग्रेजी में, दो स्कूपिंग तंत्रों के बीच महत्वपूर्ण अंतर क्या है?
उपर्युक्त उत्तरों के दौरान लेक्सिकल स्कूपिंग को बहुत अच्छी तरह से परिभाषित किया गया है: लेक्सिकली स्कॉप्ड वैरिएबल्स फ़ंक्शन के स्थानीय स्तर पर उपलब्ध हैं - या, सुलभ - जिसमें यह परिभाषित किया गया था।
हालाँकि - जैसा कि यह ओपी का फोकस नहीं है - डायनेमिक स्कोपिंग पर बहुत अधिक ध्यान नहीं गया है और इसे प्राप्त किए गए ध्यान का मतलब है कि इसे शायद थोड़ा और अधिक की आवश्यकता है (यह अन्य उत्तरों की आलोचना नहीं है, बल्कि "ओह" उस जवाब से हमें लगा कि काश "थोड़ा और" होता। तो, यहाँ थोड़ा अधिक है:
डायनामिक स्कोपिंग का अर्थ है कि फ़ंक्शन कॉल के जीवनकाल के दौरान एक चर बड़े कार्यक्रम के लिए सुलभ है - या, जबकि फ़ंक्शन निष्पादित हो रहा है। वास्तव में, विकिपीडिया वास्तव में दोनों के बीच के अंतर की व्याख्या के साथ एक अच्छा काम करता है । तो यह नहीं करने के लिए के रूप में, यहाँ पाठ है कि गतिशील ढलान का वर्णन है:
... [I] n डायनेमिक स्कोपिंग (या डायनेमिक स्कोप), यदि वैरिएबल नाम का स्कोप एक निश्चित फंक्शन है, तो इसका स्कोप वह समयावधि है, जिसके दौरान फंक्शन चल रहा होता है: फंक्शन चल रहा होता है, वैरिएबल नाम मौजूद होता है , और इसके चर के लिए बाध्य है, लेकिन फ़ंक्शन वापस आने के बाद, चर नाम मौजूद नहीं है।
लेक्सिकल स्कोप का अर्थ है कि एक फ़ंक्शन उस संदर्भ में वेरिएबल को देखता है जहां इसे परिभाषित किया गया था, और इसके आसपास के दायरे में नहीं।
यदि आप अधिक विवरण चाहते हैं, तो लिस्प में लेक्सिकल गुंजाइश कैसे काम करती है, इसे देखें । कॉमन क्रिस्प में डायनामिक और लेक्सिकल वैरिएबल में काइल क्रोनिन द्वारा चयनित उत्तर यहां के उत्तरों से बहुत स्पष्ट है।
संयोगवश मैंने केवल एक लिस्प कक्षा में इसके बारे में सीखा, और यह जावास्क्रिप्ट में भी लागू होता है।
मैंने क्रोम के कंसोल में इस कोड को चलाया।
// 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
जावास्क्रिप्ट में एक लेक्सिकल स्कोप का मतलब है कि एक फ़ंक्शन के बाहर परिभाषित किया गया एक वैरिएबल डिक्लेरेशन के बाद परिभाषित दूसरे फ़ंक्शन के अंदर पहुंच योग्य हो सकता है। लेकिन विपरीत सत्य नहीं है; किसी फ़ंक्शन के अंदर परिभाषित चर उस फ़ंक्शन के बाहर पहुंच योग्य नहीं होंगे।
जावास्क्रिप्ट में क्लोजर में इस अवधारणा का भारी उपयोग किया जाता है।
मान लीजिए कि हमारे पास नीचे का कोड है।
var x = 2;
var add = function() {
var y = 1;
return x + y;
};
अब, जब आप ऐड कहते हैं () -> यह 3 प्रिंट करेगा।
इसलिए, ऐड () फ़ंक्शन ग्लोबल वैरिएबल तक पहुंच रहा है, x
जिसे मेथड फंक्शन ऐड से पहले परिभाषित किया गया है। इसे जावास्क्रिप्ट में लेक्सिकल स्कूपिंग के कारण कहा जाता है।
add()
फ़ंक्शन जहां दिए गए कोड स्निपेट के तुरंत बाद कहा जाता है, तो यह भी प्रिंट होगा 3. लेक्सिकल स्कूपिंग का मतलब यह नहीं है कि एक फ़ंक्शन स्थानीय संदर्भ के बाहर वैश्विक चर का उपयोग कर सकता है। तो उदाहरण कोड वास्तव में यह दिखाने में मदद नहीं करता है कि लेक्सिकल स्कूपिंग का मतलब क्या है। कोड में लेक्सिकल स्कूपिंग को वास्तव में एक काउंटर उदाहरण या कोड की अन्य संभावित व्याख्याओं के स्पष्टीकरण की आवश्यकता है।
निष्पादन क्षेत्र में वर्तमान स्थिति से दिखाई देने वाले पहचानकर्ताओं (जैसे, चर, कार्य, आदि) के लेक्सिकॉन गुंजाइश को संदर्भित करता है।
- 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 का विशेष धन्यवाद ।
इस प्रश्न पर यहां एक अलग कोण है जिसे हम एक कदम पीछे ले जाकर और व्याख्या के बड़े ढांचे में स्कूपिंग की भूमिका को देख सकते हैं (एक कार्यक्रम चला रहे हैं)। दूसरे शब्दों में, कल्पना करें कि आप एक भाषा के लिए एक दुभाषिया (या संकलक) का निर्माण कर रहे थे और आउटपुट की गणना के लिए जिम्मेदार थे, एक कार्यक्रम और इसके लिए कुछ इनपुट दिए।
व्याख्या में तीन बातों का ध्यान रखना शामिल है:
राज्य - अर्थात्, चर और संदर्भित स्मृति स्थान ढेर और स्टैक पर।
उस स्थिति पर संचालन - अर्थात्, आपके कार्यक्रम में कोड की प्रत्येक पंक्ति
वह वातावरण जिसमें एक दिया गया संचालन चलता है - अर्थात्, एक ऑपरेशन पर राज्य का प्रक्षेपण ।
एक दुभाषिया एक प्रोग्राम में कोड की पहली पंक्ति पर शुरू होता है, अपने वातावरण की गणना करता है, उस वातावरण में लाइन चलाता है और कार्यक्रम की स्थिति पर इसके प्रभाव को पकड़ता है। यह कोड की अगली पंक्ति को निष्पादित करने के लिए प्रोग्राम के नियंत्रण प्रवाह का अनुसरण करता है, और प्रोग्राम के समाप्त होने तक प्रक्रिया को दोहराता है।
जिस तरह से आप किसी भी ऑपरेशन के लिए पर्यावरण की गणना करते हैं, वह प्रोग्रामिंग भाषा द्वारा निर्धारित नियमों के एक औपचारिक सेट के माध्यम से होता है। शब्द "बाइंडिंग" का उपयोग अक्सर कार्यक्रम के समग्र राज्य के मानचित्रण का वर्णन करने के लिए किया जाता है जो पर्यावरण में एक मूल्य है। ध्यान दें कि "समग्र राज्य" से हमारा तात्पर्य वैश्विक स्थिति से नहीं है, बल्कि निष्पादन में किसी भी बिंदु पर हर पहुंच योग्य परिभाषा का योग है)।
यह वह ढांचा है जिसमें स्कूपिंग समस्या को परिभाषित किया गया है। अब हमारे विकल्पों के अगले भाग के लिए।
यह डायनेमिक स्कोपिंग का सार है , जिसमें कोई भी कोड जिस पर्यावरण में चलता है वह प्रोग्राम की स्थिति के अनुसार उसके निष्पादन संदर्भ से परिभाषित होता है।
दूसरे शब्दों में, लेक्सिकल स्कोप के साथ पर्यावरण जो किसी भी कोड को देखता है वह भाषा में स्पष्ट रूप से परिभाषित एक स्कोप से जुड़ा हुआ है, जैसे कि ब्लॉक या फ़ंक्शन।
प्राचीन प्रश्न है, लेकिन यहाँ इस पर मेरा विचार है।
लेक्सिकल (स्टैटिक) स्कोप से सोर्स कोड में वैरिएबल के स्कोप का पता चलता है ।
जावास्क्रिप्ट जैसी भाषा में, जहाँ फ़ंक्शंस को पास किया जा सकता है और विविध वस्तुओं के साथ संलग्न और फिर से संलग्न किया जा सकता है, हालांकि आपके पास यह गुंजाइश हो सकती है कि उस समय फ़ंक्शन को कॉल करने पर निर्भर करेगा, लेकिन यह नहीं है। जिस तरह से डायनेमिक स्कोप होगा उस स्कोप को बदलना, और जावास्क्रिप्ट ऐसा नहीं करता, सिवाय संभवतः के साथ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
नहीं करता है। आपके द्वारा पसंद किए जाने से अधिक आप नेस्टिंग कार्य समाप्त कर सकते हैं।
वैसे, दोनों उदाहरणों में, आप यह भी देखेंगे कि आंतरिक रूप से स्कोप किए गए वैरिएबल तब भी बने रहते हैं, जब युक्त फ़ंक्शन फ़ंक्शन ने अपना कोर्स चला लिया हो। यह कहा जाता है क्लोजर , और एक नेस्टेड फ़ंक्शन के बाहरी चर तक पहुंच को संदर्भित करता है, भले ही बाहरी फ़ंक्शन समाप्त हो गया हो। जावास्क्रिप्ट को यह निर्धारित करने के लिए पर्याप्त स्मार्ट होना चाहिए कि क्या उन चर की अब आवश्यकता नहीं है, और यदि नहीं, तो कचरा उन्हें इकट्ठा कर सकता है।
मैं आम तौर पर उदाहरण के द्वारा सीखता हूं, और यहां कुछ है:
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();
यह विषय बिल्ट-इन 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"