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


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

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


7654


मूल


इन और कई उत्तरों के साथ मेरी समस्या यह है कि वे जावास्क्रिप्ट में बंद होने और व्यावहारिक परिस्थितियों में आप क्यों उपयोग करते हैं, यह समझाने के बजाय, वे एक सार, सैद्धांतिक परिप्रेक्ष्य से इसकी अपेक्षा करते हैं। आप एक टीएल के साथ खत्म हो जाते हैं; डॉ लेख जो आपको हर समय सोचने के लिए, "लेकिन, क्यों?" के माध्यम से घूमना है। मैं बस इसके साथ शुरू करूंगा: जावास्क्रिप्ट की निम्नलिखित दो वास्तविकताओं से निपटने का एक साफ तरीका है: ए। स्कोप फ़ंक्शन स्तर पर है, न कि ब्लॉक स्तर और, बी। जावास्क्रिप्ट में अभ्यास में आप जो कुछ भी करते हैं वह असीमित / घटना संचालित होता है। - Jeremy Burton
@Redsandro एक के लिए, यह इवेंट-संचालित कोड लिखने के लिए बहुत आसान बनाता है। जब कोई पृष्ठ HTML या उपलब्ध सुविधाओं के बारे में विशिष्टता निर्धारित करने के लिए लोड होता है तो मैं एक फ़ंक्शन को आग लगा सकता हूं। मैं उस फ़ंक्शन में एक हैंडलर को परिभाषित और सेट कर सकता हूं और जब भी हैंडलर को फिर से पूछे बिना बुलाया जाता है तो उस संदर्भ जानकारी को उपलब्ध कराया जाता है। एक बार समस्या हल करें, प्रत्येक पृष्ठ पर पुन: उपयोग करें जहां हैंडलर को हैंडलर पुनः-आमंत्रण पर कम ओवरहेड के साथ जरूरी है। आपने कभी भी एक ही डेटा को दो बार फिर से मैप किया है जो उस भाषा में नहीं है? क्लोजर इस तरह की चीज से बचने के लिए बहुत आसान बनाते हैं। - Erik Reppen
जावा प्रोग्रामर के लिए, संक्षिप्त उत्तर यह है कि यह एक आंतरिक वर्ग के बराबर कार्य है। एक आंतरिक वर्ग में बाहरी वर्ग के उदाहरण के लिए एक निहित सूचक भी होता है, और इसका उपयोग उसी उद्देश्य के लिए किया जाता है (यानी, ईवेंट हैंडलर बनाना)। - Boris van Schooten
इसे यहां से बेहतर समझें: javascriptissexy.com/understand-javascript-closures-with-ease। अभी भी एक की जरूरत है समापन अन्य उत्तरों को पढ़ने के बाद बंद होने पर। :) - Akhoy
मुझे यह व्यावहारिक उदाहरण बहुत उपयोगी पाया गया: youtube.com/watch?v=w1s9PgtEoJs - Abhi


जवाब:


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

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

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

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

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

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

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

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

दो एक वाक्य सारांश:

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

  • या, एक बंद एक स्टैक फ्रेम है जिसे आवंटित किया जाता है जब कोई फ़ंक्शन निष्पादन शुरू करता है, और मुक्त नहीं समारोह के बाद (जैसे कि 'स्टैक फ्रेम' ढेर के बजाय ढेर पर आवंटित किया गया था!)।

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

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 तथा say2 प्रत्येक एक समारोह के लिए एक सूचक थे।

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

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

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

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

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

के आउटपुट को देख रहे हैं say2.toString(), हम देख सकते हैं कि कोड चर को संदर्भित करता है text। अनाम कार्य संदर्भ कर सकते हैं text जो मूल्य रखता है 'Hello Bob' क्योंकि स्थानीय चर 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() फिर, फिर एक नया बंद (ढेर-फ्रेम!) बनाया गया है। पुराना gLogNumber, gIncreaseNumber, gSetNumber चर के साथ अधिलेखित कर रहे हैं नया नए बंद होने वाले कार्यों। (जावास्क्रिप्ट में, जब भी आप किसी अन्य फ़ंक्शन के अंदर फ़ंक्शन घोषित करते हैं, तो अंदर का फ़ंक्शन दोबारा बनाया जाता है से प्रत्येक समय बाहरी समारोह कहा जाता है।)

उदाहरण 5

इस उदाहरण से पता चलता है कि बंद होने में बाहरी फ़ंक्शन के अंदर घोषित होने से पहले किसी स्थानीय चर को शामिल किया गया था। ध्यान दें कि चर alice वास्तव में अज्ञात समारोह के बाद घोषित किया जाता है। अज्ञात फ़ंक्शन पहले घोषित किया गया है; और जब उस समारोह को बुलाया जाता है तो यह एक्सेस कर सकता है alice परिवर्तनीय क्योंकि alice एक ही दायरे में है (जावास्क्रिप्ट करता है परिवर्तनीय hoisting)। भी 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 का मूल्य है item2। और i ++ बढ़ेगा i मूल्य के लिए 3

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

item0 undefined
item1 undefined
item2 undefined

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

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

लिंक

धन्यवाद

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


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


6173



प्रतिभाशाली। मैं विशेष रूप से प्यार करता हूं: "जावास्क्रिप्ट में एक बंद सभी स्थानीय चर की एक प्रति रखने की तरह है, जैसे कि जब कोई फ़ंक्शन निकलता था।" - e-satis
@ ई-सैटिस - ऐसा लगता है कि शानदार, "सभी स्थानीय चर की एक प्रति, जैसे कि जब कार्य समाप्त हो गया था" भ्रामक है। यह सुझाव देता है कि चर के मानों की प्रतिलिपि बनाई गई है, लेकिन वास्तव में यह वेरिएबल्स का सेट है जो फ़ंक्शन के बाद परिवर्तित नहीं होता है ('eval' को छोड़कर: blog.rakeshpai.me/2008/10/...)। यह सुझाव देता है कि बंद होने से पहले फ़ंक्शन को वापस करना होगा, लेकिन बंद होने से पहले इसे बंद करने की आवश्यकता नहीं है। - dlaliberte
यह अच्छा लगता है: "जावास्क्रिप्ट में एक बंद सभी स्थानीय चर की एक प्रति रखने की तरह है, जैसे कि जब कोई फ़ंक्शन निकलता था।" लेकिन यह दो कारणों से भ्रामक है। (1) बंद करने के लिए फ़ंक्शन कॉल को बाहर निकलने की आवश्यकता नहीं है। (2) यह एक प्रति नहीं है मान स्थानीय चर के लेकिन खुद चर। (3) यह नहीं कहता कि इन चरों तक किसके पास पहुंच है। - dlaliberte
उदाहरण 5 एक "गॉचा" दिखाता है जहां कोड इरादे के अनुसार काम नहीं करता है। लेकिन यह नहीं दिखाता कि इसे कैसे ठीक किया जाए। यह दूसरा जवाब है ऐसा करने का एक तरीका दिखाता है। - Matt
मुझे यह पसंद है कि यह पोस्ट बड़े बोल्ड अक्षरों के साथ कैसे शुरू होता है, जिसमें कहा गया है कि "क्लोजर मैजिक नहीं हैं" और इसका पहला उदाहरण समाप्त होता है "जादू यह है कि जावास्क्रिप्ट में एक फ़ंक्शन संदर्भ में उस बंद होने के लिए एक गुप्त संदर्भ भी है"। - Andrew Macheret


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

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, और यह भी उपयोग कर सकते हैं tmp से foo

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

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बंद हो रहा है, यह भी बढ़ रहा है। जब भी आप कॉल करेंगे तो इसे बढ़ाया जाएगा 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 ऑब्जेक्ट्स के साथ मेमोरी लीक का आधार है।


3808



@feeela: हाँ, हर जेएस फ़ंक्शन बंद हो जाता है। संदर्भित नहीं किए जाने वाले वेरिएबल को आधुनिक जेएस इंजनों में कचरा संग्रह के लिए योग्य बनाया जाएगा, लेकिन यह इस तथ्य को नहीं बदलेगा कि जब आप निष्पादन संदर्भ बनाते हैं, तो उस संदर्भ में समापन निष्पादन संदर्भ, और इसके चर, और वह फ़ंक्शन एक ऑब्जेक्ट है जिसमें उस मूल संदर्भ को बनाए रखते हुए, एक भिन्न चरणीय क्षेत्र में स्थानांतरित करने की क्षमता है। वह बंद है।
@ एली मैंने अभी पाया है कि मैंने जो जेएसफ़ाइल प्रदान किया है वह वास्तव में कुछ भी साबित नहीं करता है, क्योंकि delete विफल रहता है। फिर भी, इस कार्य को परिभाषित करने वाले कथन को निष्पादित करते समय, [[स्कोप]] (और अंततः अपने स्वयं के शब्दावली पर्यावरण के आधार के रूप में उपयोग के रूप में कार्य के रूप में कार्य करने वाला लेक्सिकल वातावरण) निर्धारित किया जाता है। इसका मतलब है कि समारोह है निष्पादन के दायरे की पूरी सामग्री पर बंद होना, भले ही यह वास्तव में किस मूल्य को संदर्भित करता है और क्या यह गुंजाइश से बच निकलता है। कृपया खंड 13.2 और 10 देखें कल्पना - Asad Saeeduddin
यह तब तक एक अच्छा जवाब था जब तक कि यह प्राचीन प्रकार और संदर्भों को समझाता नहीं था। यह पूरी तरह से गलत हो जाता है और प्रतिलिपि बनाने के बारे में बात करता है, जिसका वास्तव में कुछ भी करने के लिए कुछ भी नहीं है। - Ry-♦
क्लोजर क्लास-आधारित, ऑब्जेक्ट उन्मुख प्रोग्रामिंग के लिए जावास्क्रिप्ट का उत्तर है। जेएस वर्ग आधारित नहीं है, इसलिए किसी को कुछ चीजों को लागू करने के लिए एक और तरीका खोजना पड़ा जिसे अन्यथा लागू नहीं किया जा सका। - Barth Zalewski
यह स्वीकार्य उत्तर होना चाहिए। जादू आंतरिक समारोह में कभी नहीं होता है। यह तब होता है जब बाह्य चर को एक चर में असाइन किया जाता है। यह आंतरिक फ़ंक्शन के लिए एक नया निष्पादन संदर्भ बनाता है, इसलिए "निजी चर" जमा किया जा सकता है। निस्संदेह यह चर के बाद से बाहरी कार्य को संदर्भ बनाए रखा है। पहला जवाब सिर्फ यह समझने के बिना पूरी चीज को और जटिल बनाता है कि वास्तव में क्या होता है। - Albert Gao


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

पुराने अल्बर्ट की तरह कहा: "यदि आप इसे छह साल के लिए समझा नहीं सकते हैं, तो आप वास्तव में इसे स्वयं नहीं समझते हैं।" ठीक है, मैंने 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();

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

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

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


2253



मैं वास्तव में इस स्पष्टीकरण से प्यार करता हूँ। जो लोग इसे पढ़ते हैं और उनका पालन नहीं करते हैं, उनके लिए समानता है: राजकुमारी () फ़ंक्शन एक जटिल दायरा है जिसमें निजी डेटा होता है। समारोह के बाहर, निजी डेटा को देखा या उपयोग नहीं किया जा सकता है। राजकुमारी अपनी कल्पना (निजी डेटा) में यूनिकोरन्स, ड्रेगन, रोमांच इत्यादि रखती है और उगाए जाने वाले लोग उन्हें खुद के लिए नहीं देख सकते हैं। लेकिन राजकुमारी की कल्पना को बंद करने में पकड़ा गया है story()समारोह, जो एकमात्र इंटरफ़ेस है littleGirl उदाहरण जादू की दुनिया में उजागर होता है। - Patrick M
अच्छा यहाँ story बंद है लेकिन कोड था var story = function() {}; return story; फिर littleGirl बंद हो जाएगा। कम से कम यह इंप्रेशन है कि मैं से मिलता हूं एमडीएन के बंद होने के साथ 'निजी' विधियों का उपयोग: "वे तीन सार्वजनिक कार्य बंद हैं जो समान वातावरण साझा करते हैं।" - icc97
@ आईसीसी 7 9, हां, story एक गुंजाइश के भीतर प्रदान किए गए पर्यावरण का संदर्भ देने वाला एक बंद है princess। princess एक और भी है अस्पष्ट बंद, यानी princess और यह littleGirl ए के लिए कोई संदर्भ साझा करेंगे parents सरणी जो पर्यावरण / दायरे में वापस मौजूद होगी जहां littleGirl मौजूद है और princess परिभषित किया। - Jacob Swartwood
@ बेंजामिन क्रुप मैंने एक स्पष्ट कोड टिप्पणी जोड़ा है जो दर्शाता है कि शरीर के भीतर और अधिक संचालन हैं princess क्या लिखा है की तुलना में। दुर्भाग्य से यह कहानी अब इस धागे पर जगह से थोड़ी दूर है। मूल रूप से सवाल "5yr पुरानी के लिए जावास्क्रिप्ट बंद करने की व्याख्या" करने के लिए कह रहा था; मेरी प्रतिक्रिया केवल एक ही थी जिसने इसे करने का भी प्रयास किया। मुझे संदेह नहीं है कि यह बुरी तरह विफल रहा होगा, लेकिन कम से कम इस प्रतिक्रिया में 5yr पुरानी रुचि रखने का मौका हो सकता है। - Jacob Swartwood
असल में, मेरे लिए यह सही अर्थ बना दिया। और मुझे स्वीकार करना होगा, अंत में राजकुमारियों और रोमांचों की कहानियों का उपयोग करके एक जेएस बंद करने को समझना मुझे अजीब लग रहा है। - Crystallize


सवाल को गंभीरता से लेते हुए, हमें पता होना चाहिए कि एक सामान्य 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();

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

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

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

693



असल में, भ्रमित, मेककिचन फ़ंक्शन कॉल असली बंद है, न कि रसोई वस्तु जो यह लौटती है। - dlaliberte
दूसरों के माध्यम से अपना रास्ता रखने के बाद मुझे यह जवाब यह समझने का सबसे आसान तरीका बताया गया कि बंद और क्यों। - Chetabahana
बहुत अधिक मेनू और ऐपेटाइज़र, पर्याप्त मांस और आलू नहीं। आप उस उत्तर को केवल एक छोटी सी वाक्य के साथ सुधार सकते हैं जैसे: "क्लोजर द्वारा प्रदत्त किसी भी स्कोपिंग तंत्र की कमी के कारण, एक बंद एक समारोह का मुहरबंद संदर्भ है।" - Jacob


स्ट्रॉ मैन

मुझे यह जानने क