javascript - जावास्क्रिप्ट में एक वेब पेज बनाने के लिए और उपयोगकर्ता से एक इनपुट के रूप पृष्ठभूमि रंग ले रपत




जावास्क्रिप्ट कैसे काम बंद कर देता है? (20)

आप उन अवधारणाओं के ज्ञान के साथ जावास्क्रिप्ट क्लोजर को कैसे समझाएंगे (उदाहरण के लिए फ़ंक्शंस, वेरिएबल्स और जैसे), लेकिन खुद को बंद नहीं करते हैं?

मैंने विकिपीडिया पर दिए गए स्कीम उदाहरण को देखा है, लेकिन दुर्भाग्यवश इससे मदद नहीं मिली।

https://code.i-harness.com


बच्चे हमेशा अपने माता-पिता के साथ साझा किए गए रहस्यों को याद रखेंगे, यहां तक ​​कि उनके माता-पिता के जाने के बाद भी। कार्यों के लिए यह बंद है।

जावास्क्रिप्ट कार्यों के लिए रहस्य निजी चर हैं

var parent = function() {
 var name = "Mary"; // secret
}

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

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

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

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

इसलिए, जब तक हम अभिभावक-कार्य में हैं, तब तक यह एक या अधिक बाल कार्य कर सकता है जो गुप्त स्थान से गुप्त चर साझा करते हैं।

लेकिन दुख की बात यह है कि, यदि बच्चा अपने मूल कार्य का एक निजी चर भी है, तो माता-पिता समाप्त होने पर भी मर जाएगा, और रहस्य उनके साथ मर जाएंगे।

तो जीने के लिए, बच्चे को बहुत देर हो चुकी है इससे पहले छोड़ना है

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

और अब, हालांकि मैरी "अब नहीं चल रही है", उसकी यादें खो नहीं गई हैं और उसका बच्चा हमेशा उनके नाम और अन्य रहस्यों को याद रखेगा जो उन्होंने अपने समय के दौरान साझा किए थे।

इसलिए, अगर आप बच्चे को "एलिस" कहते हैं, तो वह जवाब देगी

child("Alice") => "My name is Alice, child of Mary"

यह बताने के लिए सब कुछ है।


शुरुआती के लिए जावास्क्रिप्ट बंद

मॉरिस ऑन ट्यू द्वारा प्रस्तुत, 2006-02-21 10:19। तब से समुदाय-संपादित।

बंद जादू नहीं हैं

यह पृष्ठ बंद करने की व्याख्या करता है ताकि एक प्रोग्रामर उन्हें समझ सके - वर्किंग जावास्क्रिप्ट कोड का उपयोग कर। यह गुरु या कार्यात्मक प्रोग्रामर के लिए नहीं है।

मूल अवधारणा को गले लगाने के बाद क्लोजर को समझना मुश्किल नहीं होता है। हालांकि, किसी भी सैद्धांतिक या अकादमिक उन्मुख स्पष्टीकरण पढ़कर उन्हें समझना असंभव है!

यह आलेख प्रोग्रामर के लिए मुख्यधारा की भाषा में कुछ प्रोग्रामिंग अनुभव के साथ है, और निम्न जावास्क्रिप्ट फ़ंक्शन को कौन पढ़ सकता है:

function sayHello(name) {
  var text = 'Hello ' + name;
  var say = function() { console.log(text); }
  say();
}
sayHello('Joe');

दो संक्षिप्त सारांश

  • जब कोई फ़ंक्शन (foo) अन्य फ़ंक्शंस (बार और बाज़) घोषित करता है, तो फ़ंक्शन में बनाए गए स्थानीय चर के परिवार को समाप्त होने पर नष्ट नहीं किया जाता है। चर केवल बाहरी दुनिया के लिए अदृश्य हो जाते हैं। इसलिए फू फ़ंक्शन बार और बाज़ को चालाकी से वापस कर सकता है, और वे चर के इस बंद-बंद परिवार ("बंद") के माध्यम से एक-दूसरे के साथ पढ़ना, लिखना और संवाद करना जारी रख सकते हैं, जो कि किसी और के साथ दखल नहीं दे सकता है, यहां तक ​​कि कोई भी जो कॉल नहीं करता भविष्य में फिर से foo।

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

बंद करने का एक उदाहरण

निम्न कोड किसी फ़ंक्शन का संदर्भ देता है:

function sayHello2(name) {
  var text = 'Hello ' + name; // Local variable
  var say = function() { console.log(text); }
  return say;
}
var say2 = sayHello2('Bob');
say2(); // logs "Hello Bob"

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

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

उपरोक्त कोड में एक बंद है क्योंकि अज्ञात फ़ंक्शन function() { console.log(text); } function() { console.log(text); } को एक और समारोह के अंदर घोषित किया गया है, इस उदाहरण में sayHello2() । जावास्क्रिप्ट में, यदि आप किसी अन्य फ़ंक्शन के अंदर function कीवर्ड का उपयोग करते हैं, तो आप एक बंद कर रहे हैं।

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

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

function() { console.log(text); } // Output of say2.toString();

say2.toString() के आउटपुट को देखते हुए, हम देख सकते हैं कि कोड वेरिएबल text को संदर्भित करता है। अज्ञात फ़ंक्शन text को संदर्भित कर सकता है जिसमें 'Hello Bob' मान होता है क्योंकि sayHello2() के स्थानीय चर को sayHello2() को बंद में गुप्त रूप से जिंदा रखा गया है।

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

और ज्यादा उदाहरण

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

उदाहरण 3

यह उदाहरण दिखाता है कि स्थानीय चर की प्रतिलिपि बनाई गई नहीं है - उन्हें संदर्भ द्वारा रखा जाता है। ऐसा लगता है कि बाहरी कार्य मौजूद होने के बावजूद स्टैक-फ्रेम स्मृति में जीवित रहता है!

function say667() {
  // Local variable that ends up within closure
  var num = 42;
  var say = function() { console.log(num); }
  num++;
  return say;
}
var sayNumber = say667();
sayNumber(); // logs 43

उदाहरण 4

सभी तीन वैश्विक कार्यों में एक ही बंद होने का एक आम संदर्भ है क्योंकि वे सभी को setupSomeGlobals() करने के लिए एक ही कॉल के भीतर घोषित किया जाता है।

var gLogNumber, gIncreaseNumber, gSetNumber;
function setupSomeGlobals() {
  // Local variable that ends up within closure
  var num = 42;
  // Store some references to functions as global variables
  gLogNumber = function() { console.log(num); }
  gIncreaseNumber = function() { num++; }
  gSetNumber = function(x) { num = x; }
}

setupSomeGlobals();
gIncreaseNumber();
gLogNumber(); // 43
gSetNumber(5);
gLogNumber(); // 5

var oldLog = gLogNumber;

setupSomeGlobals();
gLogNumber(); // 42

oldLog() // 5

तीन कार्यों को एक ही बंद करने के लिए साझा किया गया है - setupSomeGlobals() के स्थानीय चर setupSomeGlobals() जब तीन कार्यों को परिभाषित किया गया था।

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

उदाहरण 5

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

function sayAlice() {
    var say = function() { console.log(alice); }
    // Local variable that ends up within closure
    var alice = 'Hello Alice';
    return say;
}
sayAlice()();// logs "Hello Alice"

ट्रिकी: यह भी ध्यान रखें कि say चर भी बंद होने के अंदर है, और किसी भी अन्य फ़ंक्शन द्वारा एक्सेस किया जा सकता है जिसे sayAlice() भीतर घोषित किया जा सकता है, या इसे अंदर के फ़ंक्शन के भीतर रिकर्सिव रूप से एक्सेस किया जा सकता है।

उदाहरण 6

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

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

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        var item = 'item' + i;
        result.push( function() {console.log(item + ' ' + list[i])} );
    }
    return result;
}

function testList() {
    var fnlist = buildList([1,2,3]);
    // Using j only to help prevent confusion -- could use i.
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

 testList() //logs "item2 undefined" 3 times

लाइन result.push( function() {console.log(item + ' ' + list[i])} परिणाम सरणी में तीन बार अज्ञात फ़ंक्शन का संदर्भ जोड़ता है। यदि आप अज्ञात कार्यों से परिचित नहीं हैं यह ऐसा है:

pointer = function() {console.log(item + ' ' + list[i])};
result.push(pointer);

ध्यान दें कि जब आप उदाहरण चलाते हैं, तो "item2 undefined" तीन बार लॉग होता है! ऐसा इसलिए है क्योंकि पिछले उदाहरणों की तरह, buildList लिए स्थानीय चर के लिए केवल एक बंद है (जिसके result , i और item )। जब अज्ञात फ़ंक्शन लाइन fnlist[j]() पर कॉल किए जाते हैं; वे सभी एक ही बंद होने का उपयोग करते हैं, और वे उस बंद के भीतर i और item लिए वर्तमान मान का उपयोग करते हैं (जहां i पास 3 मान है क्योंकि लूप पूरा हो गया था, और item में 'item2' का मान है)। ध्यान दें कि हम 0 से अनुक्रमणित कर रहे हैं इसलिए item में item का मान है। और i ++ i मूल्य 3

यह देखने में मददगार हो सकता है कि क्या होता है जब भिन्न कीवर्ड के माध्यम से फ़ंक्शन-स्कोप्ड वेरिएबल घोषणा के बजाय वेरिएबल item की ब्लॉक-स्तरीय घोषणा का उपयोग किया जाता है ( let कीवर्ड के माध्यम से)। यदि वह परिवर्तन किया जाता है, तो सरणी result में प्रत्येक अज्ञात फ़ंक्शन का अपना बंद होना होता है; जब उदाहरण चलाया जाता है तो आउटपुट निम्नानुसार होता है:

item0 undefined
item1 undefined
item2 undefined

यदि वेरिएबल i को var बजाय let भी परिभाषित किया गया है, तो आउटपुट है:

item0 1
item1 2
item2 3

उदाहरण 7

इस अंतिम उदाहरण में, मुख्य समारोह में प्रत्येक कॉल एक अलग बंद बनाता है।

function newClosure(someNum, someRef) {
    // Local variables that end up within closure
    var num = someNum;
    var anArray = [1,2,3];
    var ref = someRef;
    return function(x) {
        num += x;
        anArray.push(num);
        console.log('num: ' + num +
            '; anArray: ' + anArray.toString() +
            '; ref.someVar: ' + ref.someVar + ';');
      }
}
obj = {someVar: 4};
fn1 = newClosure(4, obj);
fn2 = newClosure(5, obj);
fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4;
fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4;
obj.someVar++;
fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;
fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;

सारांश

अगर सब कुछ पूरी तरह से अस्पष्ट लगता है, तो उदाहरण के साथ खेलने के लिए सबसे अच्छी बात यह है कि। उदाहरणों को समझने से स्पष्टीकरण पढ़ना बहुत कठिन है। बंद करने और ढेर-फ्रेम, आदि की मेरी व्याख्या तकनीकी रूप से सही नहीं हैं - वे समझने में मदद करने के लिए सकल सरलीकरण हैं। एक बार मूल विचार grokked हो जाने के बाद, आप बाद में विवरण उठा सकते हैं।

अंतिम अंक:

  • जब भी आप किसी अन्य function अंदर function उपयोग function , तो बंद होने का उपयोग किया जाता है।
  • जब भी आप किसी फ़ंक्शन के अंदर eval() उपयोग करते हैं, तो एक बंद करने का उपयोग किया जाता है। आपके द्वारा eval पाठ फ़ंक्शन के स्थानीय चर का संदर्भ दे सकता है, और eval भीतर आप eval('var foo = …') का उपयोग करके नए स्थानीय चर भी बना सकते हैं।
  • जब आप new Function(…) अंदर new Function(…) ( फंक्शन कन्स्ट्रक्टर ) का उपयोग करते हैं, तो यह बंद नहीं होता है। (नया फ़ंक्शन बाहरी फ़ंक्शन के स्थानीय चर का संदर्भ नहीं दे सकता है।)
  • जावास्क्रिप्ट में एक बंद करना सभी स्थानीय चर की एक प्रति रखने की तरह है, जैसे कि जब कोई फ़ंक्शन निकलता था।
  • शायद यह सोचने के लिए सबसे अच्छा है कि एक बंद हमेशा एक समारोह में प्रवेश किया जाता है, और स्थानीय चर को उस बंद करने के लिए जोड़ा जाता है।
  • स्थानीय चर के एक नए सेट को हर बार एक बंद करने के साथ एक समारोह कहा जाता है (यह देखते हुए कि फ़ंक्शन में इसके अंदर एक फ़ंक्शन घोषणा है, और उस अंदर के फ़ंक्शन का संदर्भ या तो लौटाया गया है या किसी बाहरी तरीके से बाहरी संदर्भ रखा गया है )।
  • दो कार्य ऐसा लग सकते हैं कि उनके पास एक ही स्रोत टेक्स्ट है, लेकिन उनके 'छिपा' बंद होने के कारण पूरी तरह से अलग व्यवहार है। मुझे नहीं लगता कि जावास्क्रिप्ट कोड वास्तव में पता लगा सकता है कि फ़ंक्शन संदर्भ में बंद होना है या नहीं।
  • यदि आप कोई गतिशील स्रोत कोड संशोधन करने की कोशिश कर रहे हैं (उदाहरण के लिए: myFunction = Function(myFunction.toString().replace(/Hello/,'Hola')); ), अगर myFunction एक बंद है तो यह काम नहीं करेगा ( बेशक, आप रनटाइम पर सोर्स कोड स्ट्रिंग प्रतिस्थापन करने के बारे में भी कभी नहीं सोचेंगे, लेकिन ...)।
  • कार्यों और mdash के भीतर फ़ंक्शन घोषणाओं के भीतर फ़ंक्शन घोषणाएं प्राप्त करना संभव है, और आप एक से अधिक स्तर पर बंद हो सकते हैं।
  • मुझे लगता है कि आम तौर पर बंद होने वाले चर के साथ दोनों कार्यों के लिए एक बंद शब्द होता है। ध्यान दें कि मैं इस आलेख में उस परिभाषा का उपयोग नहीं करता!
  • मुझे संदेह है कि जावास्क्रिप्ट में बंद होने वाले सामान्यतः कार्यात्मक भाषाओं में पाए जाते हैं।

लिंक

धन्यवाद

अगर आपने अभी बंद किया है (यहां या कहीं और!), तो मुझे आपके द्वारा सुझाए गए किसी भी बदलाव के बारे में किसी भी प्रतिक्रिया में दिलचस्पी है जो इस लेख को स्पष्ट कर सकता है। Morrisjohns.com (morris_closure @) को एक ईमेल भेजें। कृपया ध्यान दें कि मैं जावास्क्रिप्ट पर गुरु नहीं हूं - न ही बंद होने पर।

मॉरिस द्वारा मूल पोस्ट इंटरनेट आर्काइव में पाया जा सकता है।


क्या आप 5 साल की उम्र के बंद होने की व्याख्या कर सकते हैं? *

मुझे अभी भी लगता है कि Google की व्याख्या बहुत अच्छी तरह से काम करती है और संक्षेप में है:

/*
*    When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns.
*
* An important concept to learn in JavaScript.
*/

function outerFunction(someNum) {
    var someString = 'Hey!';
    var content = document.getElementById('content');
    function innerFunction() {
        content.innerHTML = someNum + ': ' + someString;
        content = null; // Internet Explorer memory leak for DOM reference
    }
    innerFunction();
}

outerFunction(1);​

* एसी # सवाल


बंद सरल हैं:

निम्नलिखित सरल उदाहरण जावास्क्रिप्ट बंद करने के सभी मुख्य बिंदुओं को शामिल करता है। *

यहां एक कारखाना है जो कैलकुलेटर उत्पन्न करता है जो जोड़ और गुणा कर सकता है:

function make_calculator() {
  var n = 0; // this calculator stores a single number n
  return {
    add: function(a) {
      n += a;
      return n;
    },
    multiply: function(a) {
      n *= a;
      return n;
    }
  };
}

first_calculator = make_calculator();
second_calculator = make_calculator();

first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400

first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000

मुख्य बिंदु: प्रत्येक कॉल make_calculatorएक नया स्थानीय चर बनाने के लिए बनाता है n, जो उस कैलक्यूलेटर द्वारा उपयोग करने योग्य है addऔर रिटर्न के multiplyबाद लंबे समय तक कार्य करता make_calculatorहै।

यदि आप स्टैक फ्रेम से परिचित हैं, तो ये कैलकुलेटर अजीब लगते हैं: वे रिटर्न के nबाद कैसे पहुंच सकते हैं make_calculator? जवाब यह कल्पना करना है कि जावास्क्रिप्ट "स्टैक फ्रेम" का उपयोग नहीं करता है, लेकिन इसके बजाय "हीप फ्रेम" का उपयोग करता है, जो फ़ंक्शन कॉल के बाद जारी रह सकता है जो उन्हें वापस कर देता है।

आंतरिक कार्यों जैसे कि , addऔर multiplyबाहरी फ़ंक्शन ** में घोषित चर का उपयोग करने वाले आंतरिक कार्यों को बंद कर दिया जाता है ।

यह बंद करने के लिए बहुत कुछ है।


* उदाहरण के लिए, यह किसी अन्य उत्तर में दिए गए "क्लोजर्स फॉर डमीज" आलेख में सभी बिंदुओं को शामिल करता है , उदाहरण 6 को छोड़कर, जो आसानी से दिखाता है कि चर घोषित किए जाने से पहले इसका उपयोग किया जा सकता है, जानने के लिए एक अच्छा तथ्य है लेकिन बंद होने से पूरी तरह से असंबंधित है। यह स्वीकार्य उत्तर में सभी बिंदुओं को भी शामिल करता है , अंक (1) को छोड़कर जो उनके तर्कों को स्थानीय चर (नामित फ़ंक्शन तर्क) में कॉपी करते हैं, और (2) जो संख्याओं की प्रतिलिपि बनाना एक नया नंबर बनाता है, लेकिन ऑब्जेक्ट संदर्भ की प्रतिलिपि बनाना आपको एक ही वस्तु का एक और संदर्भ देता है। ये जानने के लिए भी अच्छे हैं लेकिन फिर से बंद करने के लिए पूरी तरह से असंबंधित हैं। यह इस उत्तर में उदाहरण के समान ही है लेकिन थोड़ा छोटा और कम सार है। यह बिंदु को कवर नहीं करता हैयह उत्तर या यह टिप्पणी , जो कि जावास्क्रिप्ट वर्तमान को प्लग करना मुश्किल बनाता हैआपके आंतरिक फ़ंक्शन में लूप वैरिएबल का मान: "प्लग इन" चरण केवल एक सहायक फ़ंक्शन के साथ किया जा सकता है जो आपके आंतरिक फ़ंक्शन को संलग्न करता है और प्रत्येक लूप पुनरावृत्ति पर लगाया जाता है। (कड़ाई से बोलते हुए, आंतरिक फ़ंक्शन वेल्फ़ फ़ंक्शन की प्रतिलिपि को प्रतिलिपि बनाने की बजाय प्रतिलिपि की प्रतिलिपि तक पहुंचता है।) फिर, बंद होने पर बहुत उपयोगी, लेकिन बंद होने का यह हिस्सा नहीं है या यह कैसे काम करता है। एमएल जैसे कार्यात्मक भाषाओं में अलग-अलग काम करने वाले बंद होने के कारण अतिरिक्त भ्रम है, जहां स्टोरेज स्पेस के बजाय वैरिएबल मूल्यों से बंधे होते हैं, जो एक तरह से बंद करने को समझने वाले लोगों की निरंतर धारा प्रदान करते हैं (अर्थात् "प्लग इन" तरीके) जावास्क्रिप्ट के लिए बस गलत है, जहां चर हमेशा भंडारण स्थान से बंधे होते हैं, और कभी भी मूल्यों के लिए नहीं।

** कोई बाहरी कार्य, यदि कई घोंसला हैं, या यहां तक ​​कि वैश्विक संदर्भ में भी, क्योंकि यह उत्तर स्पष्ट रूप से बताता है।


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

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

यह हमेशा 16 लॉग करेगा, क्योंकि bar x को एक्सेस कर सकता है जिसे foo लिए तर्क के रूप में परिभाषित किया गया था, और यह foo से tmp तक भी पहुंच सकता है।

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

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2); // bar is now a closure.
bar(10);

उपर्युक्त फ़ंक्शन 16 लॉग भी करेगा, क्योंकि bar अभी भी x और tmp संदर्भ ले सकता है, भले ही यह अब दायरे के अंदर न हो।

हालांकि, चूंकि tmp अभी भी बंद के बंद होने के आसपास लटक रहा है, इसलिए इसे भी बढ़ाया जा रहा है। जब भी आप bar कॉल करेंगे तो इसे बढ़ाया जाएगा।

बंद करने का सबसे सरल उदाहरण यह है:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

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

उनमें से एक सूची लौटने या उन्हें वैश्विक चर में सेट करके, एक से अधिक बंद करने का कार्य संभव बनाना संभव है। ये सभी एक ही x और एक ही tmp देखेंगे, वे अपनी प्रतियां नहीं बनाते हैं।

यहां संख्या x एक शाब्दिक संख्या है। जावास्क्रिप्ट में अन्य अक्षरों के साथ, जब foo कहा जाता है, तो संख्या x को foo में इसकी तर्क x रूप में कॉपी किया जाता है।

दूसरी ओर, ऑब्जेक्ट्स से निपटने के दौरान जावास्क्रिप्ट हमेशा संदर्भों का उपयोग करता है। यदि कहें, तो आपने किसी ऑब्जेक्ट के साथ foo कहा है, जो क्लोजर लौटाता है वह उस मूल ऑब्जेक्ट को संदर्भित करेगा!

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    console.log(x.memb);
  }
}

var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

जैसा कि अपेक्षित है, bar(10) लिए प्रत्येक कॉल x.memb । क्या उम्मीद नहीं की जा सकती है, यह है कि x बस वही वस्तु का जिक्र कर रहा है जैसे age परिवर्तनीय! bar दो कॉल करने के बाद, age.memb 2 होगा! यह संदर्भ HTML ऑब्जेक्ट्स के साथ मेमोरी लीक का आधार है।


फॉरवर्ड: यह जवाब तब लिखा गया था जब प्रश्न था:

पुराने अल्बर्ट की तरह कहा: "यदि आप इसे छह साल के लिए समझा नहीं सकते हैं, तो आप वास्तव में इसे स्वयं नहीं समझते हैं।" ठीक है, मैंने 27 साल के मित्र को जेएस बंद करने की व्याख्या करने की कोशिश की और पूरी तरह असफल रहा।

क्या कोई इस बात पर विचार कर सकता है कि मैं 6 वर्ष का हूं और उस विषय में अजीब दिलचस्पी लेता हूं?

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

मुश्किल अवधारणाओं को समझते समय मैं समानता और रूपक का बड़ा प्रशंसक हूं, इसलिए मुझे एक कहानी के साथ अपना हाथ आज़माएं।

एक ज़माने में:

एक राजकुमारी थी ...

function princess() {

वह रोमांच से भरा एक अद्भुत दुनिया में रहती थी। वह अपने राजकुमार चर्मिंग से मुलाकात की, एक यूनिकॉर्न पर अपनी दुनिया भर में घूमती हुई, ड्रेगन से लड़ने, जानवरों से बात करने का सामना करना पड़ा, और कई अन्य fantastical चीजें।

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

लेकिन उसे हमेशा कामों और उगाहने की अपनी सुस्त दुनिया में वापस लौटना होगा।

    return {

और वह अक्सर उन्हें राजकुमारी के रूप में अपने नवीनतम अद्भुत साहसिक के बारे में बताती थी।

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

लेकिन वे सब एक छोटी लड़की देखेंगे ...

var littleGirl = princess();

... जादू और कल्पना के बारे में कहानियां कह रही है।

littleGirl.story();

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

लेकिन हम असली सच्चाई जानते हैं; कि राजकुमारी के साथ छोटी लड़की अंदर ...

... वास्तव में अंदर एक छोटी लड़की के साथ एक राजकुमारी है।


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

बचपन के विकास पर: 5 से 7 साल यह कहता है:

आपका बच्चा दो-चरणीय दिशाओं का पालन करने में सक्षम होगा। उदाहरण के लिए, यदि आप अपने बच्चे से कहते हैं, "रसोई घर जाओ और मुझे एक कचरा बैग प्राप्त करें" वे उस दिशा को याद रखने में सक्षम होंगे।

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

रसोईघर एक बंद है जिसमें एक स्थानीय चर है, जिसे trashBags कहा जाता है। रसोई के अंदर एक समारोह है जिसे getTrashBag कहा जाता है जिसे एक कचरा बैग मिलता है और इसे वापस कर देता है।

हम जावास्क्रिप्ट में इस तरह कोड कर सकते हैं:

function makeKitchen() {
  var trashBags = ['A', 'B', 'C']; // only 3 at first

  return {
    getTrashBag: function() {
      return trashBags.pop();
    }
  };
}

var kitchen = makeKitchen();

console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A

आगे के अंक बताते हैं कि बंद क्यों दिलचस्प हैं:

  • प्रत्येक बार makeKitchen() कहा जाता है, एक नया बंद अपने स्वयं के अलग trashBags के साथ बनाया जाता है।
  • trashBags वैरिएबल प्रत्येक रसोई के अंदर स्थानीय है और बाहर पहुंच योग्य नहीं है, लेकिन getTrashBag प्रॉपर्टी पर आंतरिक फ़ंक्शन के पास इसका उपयोग होता है।
  • प्रत्येक फंक्शन कॉल बंद हो जाती है, लेकिन बंद होने के अंदर से बंद होने तक कोई आंतरिक आवश्यकता नहीं होती है, जिसे बंद करने के अंदर से एक्सेस किया जा सकता है। getTrashBag फ़ंक्शन के साथ ऑब्जेक्ट को वापस करने से यह यहां होता है।

बंद पर विकिपीडिया :

कंप्यूटर विज्ञान में, एक क्लोजर एक समारोह है जिसमें उस फ़ंक्शन के नॉनोकोकल नाम (फ्री चर) के लिए एक संदर्भ वातावरण है।

तकनीकी रूप से, JavaScript , प्रत्येक कार्य एक बंद है । यह हमेशा आसपास के दायरे में परिभाषित चर के लिए एक पहुंच है।

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

क्लोजर का उपयोग अक्सर कुछ छिपे हुए निजी डेटा के साथ कार्यों को बनाने के लिए किया जाता है (लेकिन यह हमेशा मामला नहीं है)।

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

ईएमएस

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


Dlaliberte द्वारा पहली बिंदु के लिए उदाहरण:

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

var i;
function foo(x) {
    var tmp = 3;
    i = function (y) {
        console.log(x + y + (++tmp));
    }
}
foo(2);
i(3);

छः वर्षीय के लिए एक जवाब (मानते हुए कि वह जानता है कि कोई फ़ंक्शन क्या है और क्या चर है, और कौन सा डेटा है):

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

function the_closure() {
  var x = 4;
  return function () {
    return x; // Here, we look back inside the_closure for the value of x
  }
}

var myFn = the_closure();
myFn(); //=> 4

इसे समझाने का एक और वास्तव में सरल तरीका दायरे के मामले में है:

जब भी आप एक बड़े दायरे के अंदर एक छोटा सा गुंजाइश बनाते हैं, तो छोटे दायरे हमेशा बड़े दायरे में क्या देख पाएंगे।


ठीक है, 6 साल के बच्चे के साथ बात करते हुए, मैं संभवतः निम्नलिखित संगठनों का उपयोग करूंगा।

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

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

एक उन्नत बच्चे के लिए मैं निम्नलिखित की तरह कुछ डालूँगा। यह सही नहीं है, लेकिन यह आपको इस बारे में महसूस करता है कि यह क्या है:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

जैसा कि आप देख सकते हैं, कमरे में छोड़े गए खिलौने अभी भी भाई के माध्यम से सुलभ हैं और इससे कोई फर्क नहीं पड़ता कि कमरा लॉक है या नहीं। इसके साथ खेलने के लिए यहां एक jsbin है।


मुझे पता है कि पहले से ही बहुत सारे समाधान हैं, लेकिन मुझे लगता है कि इस छोटी और सरल लिपि अवधारणा को प्रदर्शित करने के लिए उपयोगी हो सकती है:

// makeSequencer will return a "sequencer" function
var makeSequencer = function() {
    var _count = 0; // not accessible outside this function
    var sequencer = function () {
        return _count++;
    }
    return sequencer;
}

var fnext = makeSequencer();
var v0 = fnext();     // v0 = 0;
var v1 = fnext();     // v1 = 1;
var vz = fnext._count // vz = undefined

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

एक बंद करना एक ऐसा फ़ंक्शन है जिसमें किसी अन्य फ़ंक्शन के दायरे (इसके चर और फ़ंक्शन) तक पहुंच होती है। एक बंद करने का सबसे आसान तरीका एक समारोह के भीतर एक समारोह के साथ है; कारण यह है कि जावास्क्रिप्ट में एक फ़ंक्शन के पास हमेशा इसके फ़ंक्शन के दायरे तक पहुंच होती है।

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    innerFunction();
}

outerFunction();

अलर्ट: बंदर

उपर्युक्त उदाहरण में, बाहरी फ़ंक्शन को कॉल किया जाता है जो बदले में आंतरिक फ़ंक्शन को कॉल करता है। ध्यान दें कि बाहरीवृत्त के लिए outerVar कैसे उपलब्ध है, यह बाहरी तरफ के मूल्य को सही ढंग से सतर्क करके प्रमाणित है।

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

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

अलर्ट: बंदर

संदर्भ ToonerFunction बाहरी फ़ंक्शन () पर सेट है, जो केवल आंतरिक फ़ंक्शन का संदर्भ देता है। जब संदर्भ ToInnerFunction कहा जाता है, यह बाहरी वार देता है। दोबारा, जैसा कि ऊपर दिया गया है, यह दर्शाता है कि आंतरिक समारोह के बाहरी बाहरी, बाहरी कार्यक्षमता का एक चर है। इसके अलावा, यह ध्यान रखना दिलचस्प है कि निष्कर्ष निष्पादन समाप्त होने के बाद भी यह इस पहुंच को बरकरार रखता है।

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

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

outerFunction = null;
alert(referenceToInnerFunction());

अलर्ट: बंदर अलर्ट: बंदर

लेकिन ऐसा कैसे है? संदर्भ कैसे इंटरेक्शन फ़ंक्शन अभी भी बाहरीवार के मान को जान सकता है कि बाहरी फ़ंक्शन को शून्य पर सेट किया गया है?

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

//////////

नोट करने के करीब बंद करने के बारे में दो अन्य चीजें। सबसे पहले, बंद होने पर हमेशा इसके युक्त फ़ंक्शन के अंतिम मानों तक पहुंच होगी।

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    outerVar = "gorilla";

    innerFunction();
}

outerFunction();

अलर्ट: गोरिला

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


आप सो रहे हैं और आप दान को आमंत्रित करते हैं। आप एक एक्सबॉक्स नियंत्रक लाने के लिए दान बताते हैं।

दान पॉल को आमंत्रित करता है। दान ने पॉल को एक नियंत्रक लाने के लिए कहा। पार्टी में कितने नियंत्रक लाए गए थे?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");

एक बंद एक वस्तु की तरह है। जब भी आप कोई फ़ंक्शन कॉल करते हैं तो यह तत्काल हो जाता है।

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

अगर आप बंद हो तो एक चर शामिल है

  1. इसे असाइन करें var foo=1; या
  2. बस लिखें var foo;

यदि एक आंतरिक कार्य (किसी अन्य फ़ंक्शन के अंदर एक फ़ंक्शन) भिन्नता के साथ अपने स्वयं के दायरे में परिभाषित किए बिना ऐसे चर को एक्सेस करता है, तो यह बाहरी बंद होने पर चर की सामग्री को संशोधित करता है ।

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

उदाहरण

function example(closure) {
  // define somevariable to live in the closure of example
  var somevariable = 'unchanged';

  return {
    change_to: function(value) {
      somevariable = value;
    },
    log: function(value) {
      console.log('somevariable of closure %s is: %s',
        closure, somevariable);
    }
  }
}

closure_one = example('one');
closure_two = example('two');

closure_one.log();
closure_two.log();
closure_one.change_to('some new value');
closure_one.log();
closure_two.log();

उत्पादन

somevariable of closure one is: unchanged
somevariable of closure two is: unchanged
somevariable of closure one is: some new value
somevariable of closure two is: unchanged

एक बंदरगाह वह है जहां एक आंतरिक कार्य के बाहरी कार्य में चर के लिए उपयोग होता है। यह शायद सबसे आसान एक-पंक्ति स्पष्टीकरण है जिसे आप बंद करने के लिए प्राप्त कर सकते हैं।


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

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

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

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

एक उदाहरण:

function foo (initValue) {
   //This variable is not destroyed when the foo function exits.
   //It is 'captured' by the two nested functions returned below.
   var value = initValue;

   //Note that the two returned functions are created right now.
   //If the foo function is called again, it will return
   //new functions referencing a different 'value' variable.
   return {
       getValue: function () { return value; },
       setValue: function (newValue) { value = newValue; }
   }
}

function bar () {
    //foo sets its local variable 'value' to 5 and returns an object with
    //two functions still referencing that local variable
    var obj = foo(5);

    //Extracting functions just to show that no 'this' is involved here
    var getValue = obj.getValue;
    var setValue = obj.setValue;

    alert(getValue()); //Displays 5
    setValue(10);
    alert(getValue()); //Displays 10

    //At this point getValue and setValue functions are destroyed
    //(in reality they are destroyed at the next iteration of the garbage collector).
    //The local variable 'value' in the foo is no longer referenced by
    //anything and is destroyed too.
}

bar();

ठीक है, 6 साल के बंद प्रशंसक। क्या आप बंद करने का सबसे सरल उदाहरण सुनना चाहते हैं?

आइए अगली स्थिति की कल्पना करें: एक ड्राइवर एक कार में बैठा है। वह कार एक विमान के अंदर है। विमान हवाई अड्डे पर है। ड्राइवर की क्षमता उसकी कार के बाहर चीजों तक पहुंचने के लिए, लेकिन विमान के अंदर, भले ही वह विमान हवाईअड्डा छोड़ देता है, एक बंद है। बस। जब आप 27 वर्ष की हो, तो अधिक विस्तृत स्पष्टीकरण या नीचे दिए गए उदाहरण पर देखें।

यहां बताया गया है कि मैं अपनी विमान कहानी को कोड में कैसे परिवर्तित कर सकता हूं।

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");


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

और हाँ, मैं इसे 6 साल के लिए भी अनुशंसा करता हूं - अगर 6 वर्षीय लोग बंद होने के बारे में सीख रहे हैं, तो यह तार्किक है कि वे लेख में प्रदान की गई संक्षिप्त और सरल व्याख्या को समझने के लिए तैयार हैं ।


मैंने एक इंटरैक्टिव जावास्क्रिप्ट ट्यूटोरियल एक साथ रखा है ताकि यह बताने के लिए कि कैसे काम बंद हो जाता है। बंद क्या है?

यहां उदाहरणों में से एक है:

var create = function (x) {
    var f = function () {
        return x; // We can refer to x here!
    };
    return f;
};
// 'create' takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here







closures