Osure क्लोजर ’क्या है?


432

मैंने करी के बारे में एक सवाल पूछा और बंद करने का उल्लेख किया गया। एक बंद क्या है? यह करी से कैसे संबंधित है?


22
अब वास्तव में बंद क्या है ??? कुछ जवाब कहते हैं, क्लोजर फ़ंक्शन है। कुछ लोग कहते हैं कि यह ढेर है। कुछ जवाब कहते हैं, यह "छिपा हुआ" मूल्य है। मेरी समझ में, यह फ़ंक्शन + संलग्न चर है।
रोलैंड

3
बताते हैं कि एक क्लोजर क्या है: stackoverflow.com/questions/4103750/…
डायटबुद्ध

इसके अलावा क्या एक बंद है पर एक नज़र है? Softwareengineering.stackexchange पर
B12Toaster

बताते हैं कि एक बंद और सामान्य उपयोग मामला क्या है: trungk18.com/experience/javascript-closure
Sasuke91

जवाबों:


743

चर गुंजाइश

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

function() {
  var a = 1;
  console.log(a); // works
}    
console.log(a); // fails

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

var a = 1;
function() {
  console.log(a); // works
}    
console.log(a); // works

जब किसी ब्लॉक या फंक्शन के साथ किया जाता है, तो इसके स्थानीय चरों की जरूरत नहीं होती है और आमतौर पर इसे मेमोरी से बाहर निकाल दिया जाता है।

यह है कि हम आम तौर पर चीजों को काम करने की उम्मीद करते हैं।

एक क्लोजर एक स्थायी स्थानीय वैरिएबल स्कोप है

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

स्कोप ऑब्जेक्ट और उसके सभी स्थानीय वैरिएबल फ़ंक्शन से जुड़े होते हैं और जब तक यह फ़ंक्शन बना रहता है तब तक बना रहेगा।

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

उदाहरण के लिए

यहाँ जावास्क्रिप्ट में एक बहुत ही सरल उदाहरण है जो बिंदु को दिखाता है:

outer = function() {
  var a = 1;
  var inner = function() {
    console.log(a);
  }
  return inner; // this returns a function
}

var fnc = outer(); // execute outer to get inner 
fnc();

यहां मैंने एक फ़ंक्शन के भीतर एक फ़ंक्शन को परिभाषित किया है। आंतरिक फ़ंक्शन सभी बाहरी फ़ंक्शन के स्थानीय चर तक पहुंच प्राप्त करता है, जिसमें शामिल हैं a। चर aआंतरिक कार्य के लिए गुंजाइश है।

आम तौर पर जब कोई फ़ंक्शन निकलता है, तो उसके सभी स्थानीय चर उड़ा दिए जाते हैं। हालाँकि, अगर हम आंतरिक फ़ंक्शन को वापस करते हैं और इसे एक चर में असाइन करते हैं fncताकि यह outerबाहर निकलने के बाद बनी रहे , तो चर के सभी जो गुंजाइश में थे जब innerपरिभाषित किया गया था भी बनी रहती है । चर aको बंद कर दिया गया है - यह एक बंद के भीतर है।

ध्यान दें कि चर aपूरी तरह से निजी है fnc। यह जावास्क्रिप्ट जैसे कार्यात्मक प्रोग्रामिंग भाषा में निजी चर बनाने का एक तरीका है।

जैसा कि आप अनुमान लगाने में सक्षम हो सकते हैं, जब मैं कहता हूं कि fnc()यह मूल्य प्रिंट करता है a, जो "1" है।

बंद होने के बिना एक भाषा में, चर aको इकट्ठा किया जाता था और फ़ंक्शन से outerबाहर निकलने पर फेंक दिया जाता था । Fnc को कॉल करना एक त्रुटि है क्योंकि aअब मौजूद नहीं है।

जावास्क्रिप्ट में, चर aबनी रहती है क्योंकि चर गुंजाइश तब बनाई जाती है जब फ़ंक्शन पहले घोषित किया जाता है और जब तक फ़ंक्शन मौजूद रहता है तब तक बनी रहती है।

aके दायरे से संबंधित है outer। के दायरे में innerपैरेंट पॉइंटर का दायरा होता है outerfncएक चर है जो इंगित करता है inneraजब तक बनी रहती है तब तक fncबनी रहती है। aबंद करने के भीतर है।


116
मैंने सोचा कि यह एक बहुत अच्छा और समझने में आसान उदाहरण है।
user12345613

16
भयानक स्पष्टीकरण के लिए धन्यवाद, मैंने बहुत से देखा है लेकिन यह वह समय है जो मुझे वास्तव में मिला है।
दिमित्र दिमित्रोव

2
मेरे पास इसका एक उदाहरण हो सकता है कि यह JQuery जैसी लाइब्रेरी में कैसे काम करता है जैसा कि 2 से अंतिम पैराग्राफ में कहा गया है? मुझे पूरी तरह से समझ नहीं आया।
डीपीएम

6
हाय जुब्बत, हाँ, jquery.js खोलें और पहली पंक्ति में देखें। आप देखेंगे कि एक फंक्शन खुल गया है। अब अंत में जाएं, आपको window.jQuery = विंडो दिखाई देगी। $ = jQuery। फिर फ़ंक्शन बंद हो जाता है और स्वयं निष्पादित होता है। अब आपके पास $ फ़ंक्शन तक पहुंच है, जिसके परिणामस्वरूप क्लोजर में परिभाषित अन्य कार्यों तक पहुंच है। क्या वह आपके सवाल का जवाब है?
सुपरल्यूमरी

4
वेब पर सर्वश्रेष्ठ व्याख्या। मेरे विचार से आसान तरीका है
मेंटिस

95

मैं एक उदाहरण (जावास्क्रिप्ट में) दूंगा:

function makeCounter () {
  var count = 0;
  return function () {
    count += 1;
    return count;
  }
}

var x = makeCounter();

x(); returns 1

x(); returns 2

...etc...

यह फ़ंक्शन, मेक-एनकाउंटर क्या करता है, क्या यह एक फ़ंक्शन देता है, जिसे हमने x कहा है, जो कि प्रत्येक बार उसके नाम से गिना जाएगा। चूंकि हम x को कोई पैरामीटर प्रदान नहीं कर रहे हैं, इसलिए इसे किसी भी तरह से गिनती याद रखना चाहिए। यह जानता है कि इसे लेक्सिकल स्कूपिंग के आधार पर कहां ढूंढना है - यह उस स्थान को देखना चाहिए जहां इसे मूल्य खोजने के लिए परिभाषित किया गया है। यह "छिपा हुआ" मूल्य वह है जिसे क्लोजर कहा जाता है।

यहाँ फिर से मेरा करी उदाहरण है:

function add (a) {
  return function (b) {
    return a + b;
  }
}

var add3 = add(3);

add3(4); returns 7

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


4
IDK, किस भाषा (शायद F #) को आपने उपरोक्त भाषा में उपयोग किया है। कृपया स्यूडोकोड में उपरोक्त उदाहरण दे सकते हैं? मुझे इसे समझने में कठिन समय लग रहा है।
उपयोगकर्ता

1
@ क्रुसिफाइडसॉल यह योजना है। ftp.cs.indiana.edu/pub/scheme-repository/doc/pubs/intro.txt
काइल क्रोनिन

3
@KyleCronin महान उदाहरण, धन्यवाद। प्रश्न: क्या यह कहना अधिक सही है कि "छिपे हुए मूल्य को एक बंद भाव कहा जाता है", या "वह कार्य जो मूल्य को छिपाता है वह बंद होना है"? या "मूल्य को छिपाने की प्रक्रिया बंद है"? धन्यवाद!

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

1
@ काइलक्रोनिन धन्यवाद - मेरे पास सोमवार को एक मध्यावधि योजना है। :) मेरे सिर में "बंद" अवधारणा ठोस होना चाहता था। ओपी के सवाल के इस शानदार जवाब को पोस्ट करने के लिए धन्यवाद!

58

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


14
यह केवल स्टैक नहीं है - यह एन्कोडिंग लेक्सिकल स्कोप है जो संरक्षित हैं, चाहे वे स्टैक या ढेर (या दोनों) पर संग्रहीत हों।
मैट फेनविक

38

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

उदाहरण के लिए, जब आपके पास जावास्क्रिप्ट फ़ंक्शन है:

function closed(x) {
  return x + 3;
}

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

लेकिन अगर आप इस तरह एक समारोह है:

function open(x) {
  return x*y + 3;
}

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

यह yएक परिभाषा के लिए भीख माँगता है, लेकिन यह परिभाषा समारोह का हिस्सा नहीं है - इसे कहीं और परिभाषित किया गया है, इसके "आसपास के संदर्भ" ( पर्यावरण के रूप में भी जाना जाता है ) में। कम से कम हम यही उम्मीद करते हैं: पी

उदाहरण के लिए, इसे विश्व स्तर पर परिभाषित किया जा सकता है:

var y = 7;

function open(x) {
  return x*y + 3;
}

या इसे एक फ़ंक्शन में परिभाषित किया जा सकता है जो इसे लपेटता है:

var global = 2;

function wrapper(y) {
  var w = "unused";

  return function(x) {
    return x*y + 3;
  }
}

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

उपरोक्त उदाहरण में, भीतरी समारोह (क्योंकि हम यह जरूरत नहीं थी, जिसे हम एक नाम देना नहीं था) एक है खुला अभिव्यक्ति क्योंकि चर yउस में है मुक्त - इसकी परिभाषा समारोह के बाहर है, समारोह जो यह लपेटता में । पर्यावरण कि अज्ञात समारोह के लिए चर का सेट है:

{
  global: 2,
  w: "unused",
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

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

{
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

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

इसके पीछे के सिद्धांत पर और अधिक: https://stackoverflow.com/a/36878651/434562

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

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


1
एक सादृश्य जो शुरुआती लोगों की मदद कर सकता है , वह सभी ढीले छोरों को बंद कर देता है, जो एक व्यक्ति तब करता है जब वे बंद करना चाहते हैं (या यह सभी आवश्यक संदर्भों को हल करता है , या ...)। ठीक है, इसने मुझे इस तरह सोचने में मदद की: ओ)
विल क्रॉफर्ड

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

29

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

def outer (a):
    b = "variable in outer()"
    def inner (c):
        print a, b, c
    return inner

# Now the return value from outer() can be saved for later
func = outer ("test")
func (1) # prints "test variable in outer() 1

23

क्लोजर की समझ को सुविधाजनक बनाने में मदद करने के लिए यह जांचना उपयोगी हो सकता है कि उन्हें प्रक्रियात्मक भाषा में कैसे लागू किया जा सकता है। यह स्पष्टीकरण योजना में क्लोजर के सरलीकृत कार्यान्वयन का पालन करेगा।

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

(define x 3)

(define y 4)

(+ x y) returns 7

परिभाषित भाव x के लिए स्थान में मान 3 और y के लिए स्थान में मूल्य 4 को संग्रहीत करते हैं। तब जब हम कॉल (+ xy) करते हैं, तो दुभाषिया नेमस्पेस में मूल्यों को देखता है और ऑपरेशन करने और 7 को वापस करने में सक्षम होता है।

हालाँकि, स्कीम में ऐसे भाव हैं जो आपको एक प्रतीक के मूल्य को अस्थायी रूप से ओवरराइड करने की अनुमति देते हैं। यहाँ एक उदाहरण है:

(define x 3)

(define y 4)

(let ((x 5))
   (+ x y)) returns 9

x returns 3

कीवर्ड क्या करता है मान 5 के रूप में x के साथ एक नया नामस्थान शुरू कर रहा है। आप देखेंगे कि यह अभी भी देखने में सक्षम है कि y 4 है, 9 को वापस किया गया योग बना रहा है। आप यह भी देख सकते हैं कि एक बार एक्स का एक्सप्रेशन समाप्त हो गया है। is back to be 3. इस अर्थ में, x को स्थानीय मान द्वारा अस्थायी रूप से मास्क किया गया है।

प्रक्रियात्मक और वस्तु-उन्मुख भाषाओं की एक समान अवधारणा है। जब भी आप किसी फ़ंक्शन में एक वैरिएबल घोषित करते हैं जिसमें एक वैश्विक वैरिएबल के समान नाम होता है तो आपको समान प्रभाव मिलता है।

हम इसे कैसे लागू करेंगे? एक सरल तरीका एक लिंक की गई सूची के साथ है - सिर में नया मान होता है और पूंछ में पुराने नाम स्थान होते हैं। जब आपको एक प्रतीक देखने की आवश्यकता होती है, तो आप सिर पर शुरू करते हैं और पूंछ के नीचे अपना काम करते हैं।

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

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns ?

हम x को 3 और प्लस-x को इसके पैरामीटर, y, और x के मान के रूप में परिभाषित करते हैं। अंत में हम प्लस-एक्स को एक ऐसे वातावरण में कहते हैं जहां x को नए x द्वारा मास्क किया गया है, यह एक मूल्यवान है। 5. यदि हम केवल फ़ंक्शन प्लस x के लिए ऑपरेशन, (+ xy) स्टोर करते हैं, तो हम संदर्भ में हैं। x का 5 होने का परिणाम 9 होगा। यह वही है जिसे डायनेमिक स्कूपिंग कहा जाता है।

हालाँकि, स्कीम, कॉमन लिस्प और कई अन्य भाषाओं ने लेक्सिकल स्कूपिंग कहा है - ऑपरेशन (+ xy) को संचय करने के अलावा हम उस विशेष बिंदु पर नाम स्थान को भी संग्रहीत करते हैं। इस तरह, जब हम मूल्यों को देख रहे होते हैं तो हम इस संदर्भ में x को देख सकते हैं, वास्तव में 3. यह एक बंद है।

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns 7

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


ठीक है, आपके उत्तर के लिए धन्यवाद, मुझे लगता है कि मुझे आखिरकार कुछ विचार है जो बंद होने के बारे में है। लेकिन एक बड़ा सवाल है: "हम फ़ंक्शन परिभाषा के समय नेमस्पेस की स्थिति को संग्रहीत करने के लिए एक लिंक की गई सूची का उपयोग कर सकते हैं, जिससे हमें चर का उपयोग करने की अनुमति मिलती है, अन्यथा अब गुंजाइश नहीं होगी।" Why do we want to access variables that are out of scope? when we say let x = 5, we want x to be 5 and not 3. What is happening?
लेज़र

@ लेजर: क्षमा करें, यह वाक्य ज्यादा मायने नहीं रखता था, इसलिए मैंने इसे अपडेट किया। मुझे उम्मीद है कि अब यह अधिक समझ में आता है। इसके अलावा, लिंक की गई सूची को कार्यान्वयन विवरण के रूप में न समझें (क्योंकि यह बहुत ही अक्षम है) लेकिन यह कैसे किया जा सकता है, इस पर अवधारणा के एक सरल तरीके के रूप में।
काइल क्रोनिन

10

यहाँ क्लोज़र्स ने गधा क्यों मारा इसका एक वास्तविक विश्व उदाहरण है ... यह सीधे मेरे जावास्क्रिप्ट कोड से बाहर है। मैं समझाता हूं।

Function.prototype.delay = function(ms /*[, arg...]*/) {
  var fn = this,
      args = Array.prototype.slice.call(arguments, 1);

  return window.setTimeout(function() {
      return fn.apply(fn, args);
  }, ms);
};

और यहां बताया गया है कि आप इसका उपयोग कैसे करेंगे:

var startPlayback = function(track) {
  Player.play(track);  
};
startPlayback(someTrack);

अब कल्पना करें कि आप चाहते हैं कि प्लेबैक विलंब से शुरू हो, उदाहरण के लिए 5 सेकंड बाद यह कोड स्निपेट चलता है। वैसे यह आसान है delayऔर यह बंद है:

startPlayback.delay(5000, someTrack);
// Keep going, do other things

जब आप ms के delayसाथ कॉल करते हैं 5000, तो पहला स्निपेट चलता है, और पास की गई तर्कों को बंद कर देता है। फिर 5 सेकंड बाद, जब setTimeoutकॉलबैक होता है, तो क्लोजर अभी भी उन चर को बनाए रखता है, इसलिए यह मूल पैरामीटर के साथ मूल फ़ंक्शन को कॉल कर सकता है।
यह एक प्रकार का करी या फंक्शन डेकोरेशन है।

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


1
यह ध्यान दिया जाना चाहिए कि भाषा या मेजबान वस्तुओं को आमतौर पर एक बुरी चीज माना जाता है क्योंकि वे वैश्विक नामस्थान का हिस्सा हैं
जॉन कुक

9

बिना मुक्त चर वाले कार्यों को शुद्ध कार्य कहा जाता है।

एक या एक से अधिक मुक्त चर वाले कार्यों को क्लोजर कहा जाता है।

var pure = function pure(x){
  return x 
  // only own environment is used
}

var foo = "bar"

var closure = function closure(){
  return foo 
  // foo is a free variable from the outer environment
}

src: https://leanpub.com/javascriptallongesix/read#leanpub-auto-if-functions-without-free-variables-are-pure-are-closures-impure


ऐसा क्यों है? यह वास्तव में बहुत अधिक "सही रास्ते पर" है कि मुक्त चर और बाध्य चर में अंतर के साथ, और शुद्ध / बंद कार्यों और अशुद्ध / खुले कार्यों, यहाँ अन्य क्लूलेस जवाबों में से अधिकांश की तुलना में: P (कार्यों के साथ भ्रमित करने के लिए छूट) बंद किया जा रहा है)।
सासक्यू

मेरे पास कोई विचार नहीं है , वास्तव में। यही कारण है कि StackOverflow बेकार है। बस मेरे उत्तर के स्रोत को देखो। उससे कौन बहस कर सकता था?
साउंडयोगी

एसओ चूसना नहीं करता है और मैंने "फ्री वैरिएबल" शब्द के बारे में कभी नहीं सुना है
काई

मुफ्त चर का उल्लेख किए बिना बंद करने के बारे में बात करना मुश्किल है। बस उन्हें देखो। मानक सीएस शब्दावली।
कॉमड्यूब

"एक या एक से अधिक मुक्त चर वाले कार्यों को क्लोजर कहा जाता है" हालांकि एक सही परिभाषा नहीं है - क्लोजर हमेशा प्रथम श्रेणी के ऑब्जेक्ट होते हैं।
कॉमड्यूब

7

tl; डॉ

एक बंद एक फ़ंक्शन और इसका दायरा एक चर के लिए (या के रूप में इस्तेमाल) सौंपा गया है। इस प्रकार, नाम बंद: गुंजाइश और फ़ंक्शन संलग्न है और किसी अन्य इकाई की तरह ही उपयोग किया जाता है।

गहराई से विकिपीडिया शैली की व्याख्या

विकिपीडिया के अनुसार, एक बंद है:

प्रथम श्रेणी के कार्यों के साथ भाषाओं में lexically scoped name बाइंडिंग को लागू करने की तकनीक।

इसका क्या मतलब है? कुछ परिभाषाओं पर ध्यान दें।

मैं इस उदाहरण का उपयोग करके क्लोजर और अन्य संबंधित परिभाषाएं समझाऊंगा:

function startAt(x) {
    return function (y) {
        return x + y;
    }
}

var closure1 = startAt(1);
var closure2 = startAt(5);

console.log(closure1(3)); // 4 (x == 1, y == 3)
console.log(closure2(3)); // 8 (x == 5, y == 3)

प्रथम श्रेणी के कार्य

मूल रूप से इसका मतलब है कि हम किसी अन्य इकाई की तरह ही कार्यों का उपयोग कर सकते हैं । हम उन्हें संशोधित कर सकते हैं, उन्हें तर्क के रूप में पारित कर सकते हैं, उन्हें कार्यों से वापस कर सकते हैं या उन्हें चर के लिए असाइन कर सकते हैं। तकनीकी रूप से, वे प्रथम श्रेणी के नागरिक हैं , इसलिए नाम: प्रथम श्रेणी के कार्य।

उपरोक्त उदाहरण में, startAtएक अनाम ( अनाम ) फ़ंक्शन देता है जो फ़ंक्शन को सौंपा गया है closure1और closure2। इसलिए जैसा कि आप देखते हैं कि जावास्क्रिप्ट किसी भी अन्य संस्थाओं (प्रथम श्रेणी के नागरिकों) की तरह ही कार्य करता है।

नाम बंधन

नाम बंधन यह पता लगाने के बारे में है कि एक चर (पहचानकर्ता) के संदर्भ में कौन सा डेटा है । गुंजाइश वास्तव में यहां महत्वपूर्ण है, क्योंकि यह वह चीज है जो यह निर्धारित करेगी कि एक बंधन कैसे हल किया जाता है।

ऊपर के उदाहरण में:

  • आंतरिक अनाम फ़ंक्शन के दायरे में, के yलिए बाध्य है 3
  • के startAtदायरे में, या (बंद होने के आधार पर) के xलिए बाध्य है ।15

अनाम फ़ंक्शन के दायरे के अंदर, xकिसी भी मूल्य के लिए बाध्य नहीं है, इसलिए इसे ऊपरी ( startAt's) दायरे में हल करने की आवश्यकता है ।

लेपिकल स्कूपिंग

जैसा कि विकिपीडिया कहता है , गुंजाइश:

एक कंप्यूटर प्रोग्राम का क्षेत्र है जहां बाध्यकारी मान्य है: जहां नाम का उपयोग इकाई को संदर्भित करने के लिए किया जा सकता है

दो तकनीकें हैं:

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

अधिक विवरण के लिए, इस प्रश्न को देखें और विकिपीडिया पर एक नज़र डालें

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

लपेटना (बंद करना)

हमारे उदाहरण में, जब हम कॉल करते हैं startAt, तो यह (प्रथम श्रेणी) फ़ंक्शन लौटाएगा जिसे सौंपा जाएगा closure1और closure2इस तरह एक क्लोजर बनाया जाता है, क्योंकि पारित चर 1और 5सहेजे गए startAtदायरे के भीतर सहेजे जाएंगे, जो कि रिटर्न के साथ संलग्न होंगे अनाम फ़ंक्शन। जब हम इस अनाम फ़ंक्शन को उसी तर्क ( ) के माध्यम से closure1और तुरंत कहते हैं , तो इसका मान तुरंत मिल जाएगा (जैसा कि उस फ़ंक्शन का पैरामीटर है), लेकिन अनाम फ़ंक्शन के दायरे में बाध्य नहीं है, इसलिए रिज़ॉल्यूशन जारी है (lexically) ऊपरी फ़ंक्शन स्कोप (जो कि क्लोज़र में सहेजा गया था) जहां या तो बाध्य पाया जाता हैclosure23yxx15। अब हम समन के लिए सब कुछ जानते हैं, इसलिए परिणाम वापस आ सकता है, फिर मुद्रित किया जा सकता है।

अब आपको क्लोज़र को समझना चाहिए और वे कैसे व्यवहार करते हैं, जो जावास्क्रिप्ट का एक मूलभूत हिस्सा है।

Currying

ओह, और आपने यह भी सीखा कि करीना किस बारे में है: आप कई मापदंडों के साथ एक फ़ंक्शन का उपयोग करने के बजाय ऑपरेशन के प्रत्येक तर्क को पारित करने के लिए फ़ंक्शन (क्लोजर) का उपयोग करते हैं।


5

बंद करना जावास्क्रिप्ट में एक विशेषता है जहां एक फ़ंक्शन के अपने स्वयं के दायरे चर तक पहुंच होती है, बाहरी फ़ंक्शन चर तक पहुंच और वैश्विक चर तक पहुंच होती है।

बाहरी फ़ंक्शन के वापस आने के बाद भी क्लोजर की बाहरी फ़ंक्शन स्कोप तक पहुँच होती है। इसका मतलब है कि एक क्लोजर याद कर सकता है और फ़ंक्शन समाप्त होने के बाद भी इसके बाहरी फ़ंक्शन के चर और तर्कों को एक्सेस कर सकता है।

आंतरिक फ़ंक्शन अपने स्वयं के दायरे में परिभाषित चर, बाहरी फ़ंक्शन के दायरे और वैश्विक दायरे तक पहुंच सकता है। और बाहरी फ़ंक्शन अपने स्वयं के दायरे और वैश्विक दायरे में परिभाषित चर तक पहुंच सकता है।

क्लोजर का उदाहरण :

var globalValue = 5;

function functOuter() {
  var outerFunctionValue = 10;

  //Inner function has access to the outer function value
  //and the global variables
  function functInner() {
    var innerFunctionValue = 5;
    alert(globalValue + outerFunctionValue + innerFunctionValue);
  }
  functInner();
}
functOuter();  

आउटपुट 20 होगा जो अपने आंतरिक फ़ंक्शन के स्वयं चर, बाहरी फ़ंक्शन चर और वैश्विक चर मूल्य का योग करता है।


4

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

def n_times(a_thing)
  return lambda{|n| a_thing * n}
end

उपरोक्त कोड में, लैम्बडा (एक अनाम फ़ंक्शन क्रिएटर) द्वारा संदर्भित lambda(|n| a_thing * n}होने के कारण क्लोजर a_thingहै।

अब, यदि आप परिणामी अनाम फ़ंक्शन को फ़ंक्शन चर में रखते हैं।

foo = n_times(4)

फू सामान्य स्कूपिंग नियम को तोड़ देगा और आंतरिक रूप से 4 का उपयोग करना शुरू कर देगा।

foo.call(3)

१२ देता है।


2

संक्षेप में, फ़ंक्शन पॉइंटर प्रोग्राम कोड बेस (जैसे प्रोग्राम काउंटर) में एक स्थान के लिए केवल एक संकेतक है। जबकि क्लोजर = फंक्शन पॉइंटर + स्टैक फ्रेम


1

• एक बंद एक उपप्रोग्राम और संदर्भित वातावरण है जहां इसे परिभाषित किया गया था

- यदि प्रोग्राम में किसी भी मनमानी जगह से सबप्रोग्राम को बुलाया जा सकता है, तो संदर्भित वातावरण की आवश्यकता है

- एक स्थिर-स्कोप भाषा जो नेस्टेड सबप्रोग्राम की अनुमति नहीं देती है, उसे बंद होने की आवश्यकता नहीं है

- क्लोज़र केवल तभी आवश्यक हैं जब उपप्रोग्राम नेस्टिंग स्कोप में चर तक पहुंच सकता है और इसे कहीं से भी कॉल किया जा सकता है

- क्लोजर का समर्थन करने के लिए, एक कार्यान्वयन को कुछ चर के लिए असीमित सीमा प्रदान करने की आवश्यकता हो सकती है (क्योंकि एक उपप्रोग्राम एक गैर-परिवर्तनीय चर तक पहुंच सकता है जो आमतौर पर जीवित नहीं है)

उदाहरण

function makeAdder(x) {
return function(y) {return x + y;}
}
var add10 = makeAdder(10);
var add5 = makeAdder(5);
document.write(″add 10 to 20: ″ + add10(20) +
″<br />″);
document.write(″add 5 to 20: ″ + add5(20) +
″<br />″);

0

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

local old_dofile = dofile

function dofile( filename )
  if filename == nil then
    error( 'Can not use default of stdin.' )
  end

  old_dofile( filename )
end

जब कोड का यह ब्लॉक स्कोप खत्म हो जाता है (क्योंकि यह स्थानीय है), तो old_dofile का मान गायब हो जाता है, हालांकि मान को एक क्लोजर में संलग्न किया गया है, इसलिए नए पुनर्परिभाषित डॉफाइल फ़ंक्शन इसे एक्सेस कर सकते हैं, या फ़ंक्शन के साथ संग्रहित एक प्रति के रूप में संग्रहीत कर सकते हैं 'upvalue'।


0

से Lua.org :

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


0

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

var f=function(){
  var a=7;
  var g=function(){
    return a;
  }
  return g;
}

फ़ंक्शन gएक क्लोजर है: अंदर gबंद हो जाता aहै। इसलिए gएक सदस्य फ़ंक्शन के aसाथ तुलना की जा सकती है , एक क्लास फ़ील्ड के साथ तुलना की जा सकती है, और fएक क्लास के साथ फ़ंक्शन ।


0

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

Listing 2-18:
    function outerFunction(arg) {
     var variableInOuterFunction = arg;

     function bar() {
             console.log(variableInOuterFunction); // Access a variable from the outer scope
     }
     // Call the local function to demonstrate that it has access to arg
     bar(); 
    }
    outerFunction('hello closure!'); // logs hello closure!

स्रोत: http://index-of.es/Varios/Basarat%20Ali%20Syed%20(auth.)-Beginning%20Node.js-Apress%20(2014).pdf


0

कृपया अधिक गहरे में बंद को समझने के लिए कोड के नीचे एक नज़र डालें:

        for(var i=0; i< 5; i++){            
            setTimeout(function(){
                console.log(i);
            }, 1000);                        
        }

यहाँ आउटपुट क्या होगा? बंद होने के कारण 0,1,2,3,4ऐसा नहीं होगा5,5,5,5,5

तो यह कैसे हल होगा? उत्तर नीचे है:

       for(var i=0; i< 5; i++){
           (function(j){     //using IIFE           
                setTimeout(function(){
                               console.log(j);
                           },1000);
            })(i);          
        }

मुझे यह स्पष्ट करने दें, जब किसी फ़ंक्शन ने तब तक कुछ नहीं किया जब तक कि इसे 1 कोड में लूप के लिए 5 बार कॉल नहीं किया जाता है, लेकिन तुरंत कॉल नहीं किया जाता है, जब इसे 1 सेकंड के बाद कहा जाता है और यह भी अतुल्यकालिक है, तो इससे पहले कि लूप समाप्त हो जाए और वैल्यू 5 स्टोर करें var i और अंत में setTimeoutफंक्शन को पाँच बार निष्पादित करें और प्रिंट करें5,5,5,5,5

यहाँ यह IIFE यानी तत्काल इनवॉइसिंग फंक्शन एक्सप्रेशन का उपयोग करके कैसे हल किया जाता है

       (function(j){  //i is passed here           
            setTimeout(function(){
                           console.log(j);
                       },1000);
        })(i);  //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4

अधिक के लिए, कृपया क्लोजर को समझने के लिए निष्पादन संदर्भ को समझें।

  • लेट (ईएस 6 फीचर) का उपयोग करके इसे हल करने के लिए एक और उपाय है लेकिन हुड के ऊपर फ़ंक्शन के तहत काम किया जाता है

     for(let i=0; i< 5; i++){           
         setTimeout(function(){
                        console.log(i);
                    },1000);                        
     }
    
    Output: 0,1,2,3,4
    

=> अधिक विवरण:

स्मृति में, जब लूप निष्पादित चित्र नीचे की तरह बनाते हैं:

लूप 1)

     setTimeout(function(){
                    console.log(i);
                },1000);  

लूप 2)

     setTimeout(function(){
                    console.log(i);
                },1000); 

लूप 3)

     setTimeout(function(){
                    console.log(i);
                },1000); 

लूप 4)

     setTimeout(function(){
                    console.log(i);
                },1000); 

लूप 5)

     setTimeout(function(){
                    console.log(i);
                },1000);  

यहाँ मुझे निष्पादित नहीं किया गया है और फिर पूर्ण लूप के बाद, var i ने मान 5 को मेमोरी में संग्रहीत किया है, लेकिन यह हमेशा गुंजाइश है कि यह बच्चों के कार्य में दिखाई देता है इसलिए जब फ़ंक्शन setTimeoutपांच बार अंदर प्रिंट करता है तो यह प्रिंट करता है5,5,5,5,5

इसलिए इस उपयोग को हल करने के लिए IIFE जैसा कि ऊपर बताया गया है।


आपके उत्तर के लिए धन्यवाद। यदि आप स्पष्टीकरण से कोड को अलग करते हैं तो यह अधिक पठनीय होगा। (इंडेंट लाइन्स जो कोड नहीं हैं)
eMBee

0

करी: यह आपको आंशिक रूप से इसके तर्कों के एक अंश में गुजर कर किसी फ़ंक्शन का मूल्यांकन करने की अनुमति देता है। इस पर विचार करो:

function multiply (x, y) {
  return x * y;
}

const double = multiply.bind(null, 2);

const eight = double(4);

eight == 8;

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

function apple(x){
   function google(y,z) {
    console.log(x*y);
   }
   google(7,2);
}

apple(3);

// the answer here will be 21

0

बंद करना बहुत आसान है। हम इसे इस प्रकार मान सकते हैं: समापन = कार्य + इसके शाब्दिक वातावरण

निम्नलिखित कार्य पर विचार करें:

function init() {
    var name = “Mozilla”;
}

उपरोक्त मामले में बंद क्या होगा? फंक्शन इनिट () और इसके लेक्सिकल वातावरण में चर यानी नाम। बंद = init () + नाम

एक अन्य समारोह पर विचार करें:

function init() {
    var name = “Mozilla”;
    function displayName(){
        alert(name);
}
displayName();
}

यहाँ क्लोजर क्या होगा? आंतरिक फ़ंक्शन बाहरी फ़ंक्शन के चर तक पहुंच सकता है। displayName () पैरेंट फ़ंक्शन, init () में घोषित चर नाम तक पहुंच सकता है। हालाँकि, यदि वे मौजूद हैं तो डिस्प्लेनेम () में समान स्थानीय चर का उपयोग किया जाएगा।

समापन 1: init फ़ंक्शन + (नाम चर + डिस्प्लेनाम () फ़ंक्शन) -> लेक्सिकल स्कोप

क्लोजर 2: डिस्प्लेनाम फ़ंक्शन + (नाम चर) -> लेक्सिकल स्कोप


0

क्लोज़र राज्य के साथ जावास्क्रिप्ट प्रदान करते हैं।

प्रोग्रामिंग में राज्य का मतलब केवल चीजों को याद रखना है।

उदाहरण

var a = 0;

a = a + 1; // => 1
a = a + 1; // => 2
a = a + 1; // => 3

उपरोक्त मामले में, राज्य "a" चर में संग्रहीत किया जाता है। हम कई बार 1 "को" जोड़कर अनुसरण करते हैं। हम केवल ऐसा कर सकते हैं क्योंकि हम मूल्य को "याद" करने में सक्षम हैं। राज्य धारक, "a", स्मृति में वह मान रखता है।

अक्सर, प्रोग्रामिंग भाषाओं में, आप चीजों को ट्रैक करना चाहते हैं, जानकारी याद रखना और बाद में समय पर पहुंचना।

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

उदाहरण

class Bread {
  constructor (weight) {
    this.weight = weight;
  }

  render () {
    return `My weight is ${this.weight}!`;
  }
}

हम "रेंडर" विधि के भीतर से "वजन" तक कैसे पहुंच सकते हैं? खैर, राज्य के लिए धन्यवाद। क्लास ब्रेड का प्रत्येक उदाहरण "राज्य", मेमोरी में एक जगह, जहां हम उस जानकारी को स्टोर कर सकते हैं, से पढ़कर अपना वजन खुद ही प्रस्तुत कर सकते हैं।

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

उदाहरण

var n = 0;
var count = function () {
  n = n + 1;
  return n;
};

count(); // # 1
count(); // # 2
count(); // # 3

ऊपर दिए गए उदाहरण ने एक चर के साथ "राज्य रखने" का लक्ष्य प्राप्त किया। यह भी खूब रही! हालांकि, इसका नुकसान यह है कि चर ("राज्य" धारक) अब उजागर हो गया है। हम बेहतर कर सकते हैं। हम क्लोजर का उपयोग कर सकते हैं।

उदाहरण

var countGenerator = function () {
  var n = 0;
  var count = function () {
    n = n + 1;
    return n;
  };

  return count;
};

var count = countGenerator();
count(); // # 1
count(); // # 2
count(); // # 3

यह शानदार है।

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

यह शानदार क्यों है? क्योंकि किसी भी अन्य परिष्कृत और जटिल उपकरण (जैसे कक्षाएं, विधियाँ, उदाहरण, आदि) को शामिल किए बिना हम 1. छिपाने में सक्षम हैं। 2. दूर से नियंत्रण

हम राज्य को छिपाते हैं, चर "n", जो इसे एक निजी चर बनाता है! हमने एक एपीआई भी बनाया है जो इस चर को पूर्व-परिभाषित तरीके से नियंत्रित कर सकता है। विशेष रूप से, हम एपीआई को "गणना" (जैसे) कह सकते हैं और जो "दूरी" से 1 "एन" जोड़ता है। किसी भी तरह से, आकार या रूप कोई भी कभी भी एपीआई के अलावा "n" तक नहीं पहुंच पाएगा।

जावास्क्रिप्ट वास्तव में अपनी सादगी में अद्भुत है।

क्लोज़र एक बड़ा हिस्सा है कि यह क्यों है।


0

आपके संदर्भ के लिए ग्रूवी में एक सरल उदाहरण:

def outer() {
    def x = 1
    return { -> println(x)} // inner
}
def innerObj = outer()
innerObj() // prints 1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.