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


7636

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

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


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

53
@Redsandro एक के लिए, यह इवेंट-संचालित कोड को लिखने में बहुत आसान बनाता है। जब HTML या उपलब्ध सुविधाओं के बारे में विवरण निर्धारित करने के लिए पृष्ठ लोड होता है, तो मैं एक फ़ंक्शन को आग लगा सकता हूं। मैं उस फ़ंक्शन में एक हैंडलर को परिभाषित और सेट कर सकता हूं और हर बार हैंडलर को फिर से क्वेरी किए बिना उस संदर्भ की जानकारी उपलब्ध है। समस्या को एक बार हल करें, हर पृष्ठ पर फिर से उपयोग करें जहां हैंडलर को फिर से आह्वान पर कम ओवरहेड के साथ आवश्यक है। आप कभी भी उसी डेटा को एक भाषा में दो बार री-मैप करवाते हैं, जो उनके पास नहीं है? क्लोजर उस तरह की चीज से बचने के लिए बहुत आसान बनाते हैं।
एरिक रेपेने

1
@ एरिक रेपेन जवाब के लिए धन्यवाद। वास्तव में, मुझे इस कठिन closureकोड को पढ़ने के लाभों के बारे में उत्सुक था, Object Literalजिसके विरोध में खुद को पुन: उपयोग करता है और ओवरहेड को कम करता है, फिर भी 100% कम रैपिंग कोड की आवश्यकता होती है।
Redsandro

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

8
मुझे यह व्यावहारिक उदाहरण बहुत उपयोगी लगा: youtube.com/watch?v=w1s9PgtEoJs
Abhi

जवाबों:


7357

एक समापन एक जोड़ी है:

  1. एक फ़ंक्शन, और
  2. उस फ़ंक्शन के बाहरी क्षेत्र (शाब्दिक वातावरण) का संदर्भ

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

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

यदि कोई फ़ंक्शन किसी फ़ंक्शन द्वारा कॉल किया गया था, जो बदले में किसी अन्य फ़ंक्शन द्वारा कॉल किया गया था, तो बाहरी लेक्सिकल वातावरण के संदर्भ की एक श्रृंखला बनाई जाती है। इस चेन को स्कोप चेन कहा जाता है।

निम्नलिखित कोड में, innerनिष्पादित होने पर बनाए गए निष्पादन संदर्भ के शाब्दिक वातावरण के साथ एक क्लोजर बनाता fooहै, जो चर पर बंद होता है secret:

function foo() {
  const secret = Math.trunc(Math.random()*100)
  return function inner() {
    console.log(`The secret number is ${secret}.`)
  }
}
const f = foo() // `secret` is not directly accessible from outside `foo`
f() // The only way to retrieve `secret`, is to invoke `f`

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

और याद रखें: जावास्क्रिप्ट में कार्यों को चर (प्रथम श्रेणी के कार्यों) की तरह पास किया जा सकता है, जिसका अर्थ है कि कार्यक्षमता और राज्य की इन जोड़ियों को आपके कार्यक्रम के चारों ओर पारित किया जा सकता है: सी ++ में आप कक्षा के एक उदाहरण को कैसे पास कर सकते हैं।

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

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

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

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

क्लोजर का उपयोग

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

निजी उदाहरण चर

निम्नलिखित कोड में, toStringकार के विवरण पर फ़ंक्शन बंद हो जाता है।

function Car(manufacturer, model, year, color) {
  return {
    toString() {
      return `${manufacturer} ${model} (${year}, ${color})`
    }
  }
}
const car = new Car('Aston Martin','V8 Vantage','2012','Quantum Silver')
console.log(car.toString())

कार्यात्मक प्रोग्रामिंग

निम्नलिखित कोड में, फ़ंक्शन innerदोनों पर बंद हो जाता है fnऔर args

function curry(fn) {
  const args = []
  return function inner(arg) {
    if(args.length === fn.length) return fn(...args)
    args.push(arg)
    return inner
  }
}

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

const curriedAdd = curry(add)
console.log(curriedAdd(2)(3)()) // 5

इवेंट-ओरिएंटेड प्रोग्रामिंग

निम्न कोड में, फ़ंक्शन onClickचर पर बंद हो जाता है BACKGROUND_COLOR

const $ = document.querySelector.bind(document)
const BACKGROUND_COLOR = 'rgba(200,200,242,1)'

function onClick() {
  $('body').style.background = BACKGROUND_COLOR
}

$('button').addEventListener('click', onClick)
<button>Set background color</button>

modularization

निम्नलिखित उदाहरण में, सभी कार्यान्वयन विवरण तुरंत निष्पादित फ़ंक्शन अभिव्यक्ति के अंदर छिपे हुए हैं। फ़ंक्शंस tickऔर toStringनिजी राज्य के ऊपर कार्य और फ़ंक्शंस उन्हें अपना काम पूरा करने की आवश्यकता होती है। क्लोज़र ने हमें हमारे कोड को संशोधित और संक्षिप्त करने में सक्षम बनाया है।

let namespace = {};

(function foo(n) {
  let numbers = []
  function format(n) {
    return Math.trunc(n)
  }
  function tick() {
    numbers.push(Math.random() * 100)
  }
  function toString() {
    return numbers.map(format)
  }
  n.counter = {
    tick,
    toString
  }
}(namespace))

const counter = namespace.counter
counter.tick()
counter.tick()
console.log(counter.toString())

उदाहरण

उदाहरण 1

यह उदाहरण दिखाता है कि स्थानीय चर को बंद में कॉपी नहीं किया गया है: बंद होने से मूल चर खुद के लिए एक संदर्भ बनाए रखता है । यह ऐसा है जैसे कि बाहरी फ़ंक्शन के बाहर निकलने के बाद भी स्टैक-फ्रेम मेमोरी में जीवित रहता है।

function foo() {
  let x = 42
  let inner  = function() { console.log(x) }
  x = x+1
  return inner
}
var f = foo()
f() // logs 43

उदाहरण 2

निम्नलिखित कोड में, तीन विधियां log, incrementऔर updateसभी एक ही शाब्दिक वातावरण के करीब हैं।

और हर बार createObjectकहा जाता है, एक नया निष्पादन संदर्भ (स्टैक फ्रेम) बनाया जाता है और एक पूरी तरह से नया चर x, और फ़ंक्शन ( logआदि) का एक नया सेट बनाया जाता है, जो इस नए चर पर बंद हो जाता है।

function createObject() {
  let x = 42;
  return {
    log() { console.log(x) },
    increment() { x++ },
    update(value) { x = value }
  }
}

const o = createObject()
o.increment()
o.log() // 43
o.update(5)
o.log() // 5
const p = createObject()
p.log() // 42

उदाहरण 3

यदि आप उपयोग किए जा रहे चर का उपयोग कर रहे हैं var, तो सावधान रहें कि आप समझ रहे हैं कि आप किस चर को खत्म कर रहे हैं। उपयोग varकर घोषित चर को फहराया जाता है। letऔर शुरू होने के कारण आधुनिक जावास्क्रिप्ट में यह बहुत कम समस्या हैconst

निम्न कोड में, लूप के चारों ओर हर बार एक नया फ़ंक्शन innerबनाया जाता है, जो बंद हो जाता है i। लेकिन क्योंकि var iलूप के बाहर फहराया जाता है, इन सभी आंतरिक कार्यों को एक ही चर पर बंद किया जाता है, जिसका अर्थ है कि i(3) का अंतिम मूल्य तीन बार मुद्रित होता है।

function foo() {
  var result = []
  for (var i = 0; i < 3; i++) {
    result.push(function inner() { console.log(i) } )
  }
  return result
}

const result = foo()
// The following will print `3`, three times...
for (var i = 0; i < 3; i++) {
  result[i]() 
}

अंतिम बिंदु:

  • जब भी जावास्क्रिप्ट में कोई फंक्शन घोषित किया जाता है तो एक क्लोजर बनाया जाता है।
  • functionकिसी अन्य फ़ंक्शन के अंदर से लौटना एक क्लोजर का क्लासिक उदाहरण है, क्योंकि बाहरी फ़ंक्शन के अंदर की स्थिति अंतर्निहित आंतरिक फ़ंक्शन के लिए अंतर्निहित रूप से उपलब्ध है, भले ही बाहरी फ़ंक्शन ने निष्पादन पूरा कर लिया हो।
  • जब भी आप eval()किसी फ़ंक्शन के अंदर उपयोग करते हैं, तो एक क्लोजर का उपयोग किया जाता है। पाठ आप evalफ़ंक्शन के स्थानीय चर को संदर्भित कर सकते हैं, और गैर-सख्त मोड में आप उपयोग करके नए स्थानीय चर भी बना सकते हैंeval('var foo = …')
  • जब आप new Function(…)( फंक्शन कंस्ट्रक्टर) का उपयोग करते हैं किसी फ़ंक्शन के अंदर ) का करते हैं, तो यह इसके शाब्दिक वातावरण को बंद नहीं करता है: यह वैश्विक संदर्भ के बजाय बंद हो जाता है। नया फ़ंक्शन बाहरी फ़ंक्शन के स्थानीय चर का संदर्भ नहीं दे सकता है।
  • जावास्क्रिप्ट में एक बंद एक संदर्भ रखने की तरह है ( नहीं फंक्शन डिक्लेरेशन के पॉइंट पर कॉपी ) स्कोप , जो इसके बाहरी स्कोप का एक रेफरेंस रखता है, और इसी तरह, ग्लोबल ऑब्जेक्ट के टॉप पर सभी तरह गुंजाइश श्रृंखला।
  • जब कोई फ़ंक्शन घोषित किया जाता है तो एक क्लोजर बनाया जाता है; इस क्लोजर का उपयोग फंक्शन के इनवाइट होने पर एक्जीक्यूटिव कॉन्टेक्ट को कॉन्फ़िगर करने के लिए किया जाता है।
  • हर बार किसी फ़ंक्शन को स्थानीय चर का एक नया सेट बनाया जाता है।

लिंक


74
यह अच्छा लगता है: "जावास्क्रिप्ट में एक बंद सभी स्थानीय चर की एक प्रति रखने की तरह है, जैसे वे एक समारोह से बाहर होने पर थे।" लेकिन यह एक दो कारणों से भ्रामक है। (1) फ़ंक्शन कॉल को बंद करने के लिए बाहर निकलने की आवश्यकता नहीं है। (२) यह स्थानीय चरों के मूल्यों की प्रति नहीं है बल्कि स्वयं चरों का है। (३) यह नहीं कहा जाता है कि इन चरों की पहुँच किसके पास है।
dlaliberte

27
उदाहरण 5 एक "गोच" दिखाता है जहां कोड इरादा के अनुसार काम नहीं करता है। लेकिन यह नहीं दिखाता कि इसे कैसे ठीक किया जाए। यह अन्य उत्तर इसे करने का एक तरीका दिखाता है।
मैट

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

6
उदाहरण # 3 javascripts उत्थापन के साथ बंद मिश्रण है। अब मुझे लगता है कि केवल क्लोजर को समझाना काफी मुश्किल है, बिना लहराए व्यवहार में लाना। : यह मुझे सबसे ज्यादा मदद की Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created.से developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Caramba

3
ECMAScript 6 बंद होने के बारे में इस महान लेख में कुछ बदल सकता है। उदाहरण के लिए, यदि आप उदाहरण 5 में उपयोग let i = 0करते हैं var i = 0, तो testList()मूल रूप से जो आप चाहते हैं उसे प्रिंट करेंगे।
नीर

3988

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

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

function foo(x) {
  var tmp = 3;

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

  bar(10);
}

foo(2);

यह लॉग करेगा 16क्योंकि फ़ंक्शन barपैरामीटर xऔर चर पर बंद हो जाता है tmp, दोनों बाहरी फ़ंक्शन के शाब्दिक वातावरण में मौजूद हैंfoo

फ़ंक्शन barके शाब्दिक वातावरण के साथ इसके लिंक के साथ फ़ंक्शन fooएक बंद है।

एक फंक्शन को क्लोजर बनाने के लिए वापस नहीं लौटना पड़ता है । बस अपनी घोषणा के आधार पर, हर फ़ंक्शन अपने आसन्न लेक्सिकल वातावरण पर बंद हो जाता है, एक बंद करने का गठन करता है।

function foo(x) {
  var tmp = 3;

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

var bar = foo(2);
bar(10); // 16
bar(10); // 17

उपरोक्त फ़ंक्शन 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();

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

प्रत्येक फ़ंक्शन एक क्लोजर बनाता है क्योंकि प्रत्येक फ़ंक्शन का इसके बाहरी शाब्दिक वातावरण से लिंक होता है।

ध्यान दें कि चर स्वयं किसी बंद के भीतर से दिखाई देते हैं, न कि प्रतियां।


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

@ मुझे पता चला है कि मैंने जो jsField प्रदान किया है वह वास्तव में कुछ भी साबित नहीं करता है, क्योंकि deleteविफल रहता है। फिर भी, वह शाब्दिक वातावरण जिसे फ़ंक्शन [[स्कोप]] के रूप में चारों ओर ले जाएगा (और अंततः जब इसे लागू किया जाता है तो इसे अपने लेक्सिकल वातावरण के लिए एक आधार के रूप में उपयोग किया जाता है) जब यह निर्धारित किया जाता है कि फ़ंक्शन निष्पादित होता है। इसका मतलब है कि समारोह है क्रियान्वित गुंजाइश की संपूर्ण सामग्री के ऊपर बंद की जो मूल्यों यह वास्तव में करने के लिए और क्या यह गुंजाइश निकल जाता है संदर्भित करता है परवाह किए बिना। कृपया वर्गों 13.2 और 10 में देखो कल्पना
असद Saeeduddin

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

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

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

2442

प्रश्न: यह उत्तर तब लिखा गया था जब प्रश्न था:

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

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

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


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

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

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

function princess() {

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

    var adventures = [];

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

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

    /* ... */

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

    return {

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

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

लेकिन वे सभी एक छोटी लड़की है ...

var littleGirl = princess();

... जादू और फंतासी के बारे में कहानियाँ बताना।

littleGirl.story();

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

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

... सचमुच एक राजकुमारी है जिसके अंदर एक छोटी लड़की है।


340
मुझे यह स्पष्टीकरण बहुत पसंद है। जो लोग इसे पढ़ते हैं और इसका पालन नहीं करते हैं, उनके लिए सादृश्य यह है: राजकुमारी () फ़ंक्शन एक जटिल गुंजाइश है जिसमें निजी डेटा होता है। फ़ंक्शन के बाहर, निजी डेटा को देखा या एक्सेस नहीं किया जा सकता है। राजकुमारी अपनी कल्पना (निजी डेटा) में इकसिंगों, ड्रेगन, कारनामों आदि को रखती है और वयस्क लोग उन्हें अपने लिए नहीं देख सकते हैं। लेकिन राजकुमारी की कल्पना को story()समारोह के लिए बंद कर दिया गया है, जो कि एकमात्र ऐसा littleGirlउदाहरण है जिसका उदाहरण जादू की दुनिया में उजागर होता है।
पैट्रिक एम

तो यहाँ storyक्लोजर है लेकिन कोड था var story = function() {}; return story;तो littleGirlक्लोजर होगा। कम से कम यह धारणा है कि मुझे एमडीएन के क्लोजर के साथ 'निजी' तरीकों का उपयोग करना है : "वे तीन सार्वजनिक कार्य बंद हैं जो समान वातावरण साझा करते हैं।"
icc97

16
@ icc97, हाँ, storyके दायरे में प्रदान किए गए पर्यावरण को संदर्भित करने वाला एक क्लोजर है princessprincessएक अन्य निहित बंद भी है , princessऔर-और littleGirlकिसी भी संदर्भ को उस parentsसरणी में साझा करेगा जो पर्यावरण / दायरे में वापस मौजूद होगा जहां littleGirlमौजूद है और princessपरिभाषित किया गया है।
जैकब स्वार्टवुड

6
@BenjaminKrupp मैंने यह दिखाने के लिए एक स्पष्ट कोड टिप्पणी जोड़ दी है / कि princessक्या लिखा है की तुलना में शरीर के भीतर अधिक संचालन होते हैं । दुर्भाग्य से यह कहानी अब इस धागे पर एक जगह से हटकर है। मूल रूप से सवाल "5 साल पुराने जावास्क्रिप्ट को समझाने के लिए पूछ रहा था"; मेरी प्रतिक्रिया केवल एक ही थी जिसने ऐसा करने का प्रयास किया। मुझे संदेह नहीं है कि यह बुरी तरह से विफल हो गया होगा, लेकिन कम से कम इस प्रतिक्रिया के लिए 5yr पुराने हित रखने का मौका हो सकता है।
याकूब स्वार्टवुड

11
वास्तव में, मेरे लिए यह सही अर्थ है। और मुझे स्वीकार करना चाहिए, अंत में राजकुमारियों और रोमांच की कहानियों का उपयोग करके एक जेएस क्लोजर को समझना मुझे थोड़े अजीब लगता है।
क्रिस्टलीकृत करें

753

प्रश्न को गंभीरता से लेते हुए, हमें यह पता लगाना चाहिए कि 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फ़ंक्शन के साथ ऑब्जेक्ट को वापस करना यहाँ है।

6
दरअसल, भ्रमित करने वाला, मेकएंजन फ़ंक्शन कॉल वास्तविक बंद होता है, न कि किचन ऑब्जेक्ट जो वह वापस लौटता है।
dlaliberte

6
दूसरों के माध्यम से अपना रास्ता होने के बाद मुझे यह उत्तर सबसे आसान तरीका के रूप में मिला कि मैं क्या और क्यों बंद करता हूं।
चेतबाहन

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

584

द स्ट्रॉ मैन

मुझे यह जानने की जरूरत है कि कितनी बार एक बटन क्लिक किया गया है और हर तीसरे क्लिक पर कुछ करना है ...

काफी हद तक स्पष्ट समाधान

// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');

element.addEventListener("click", function() {
  // Increment outside counter
  counter++;

  if (counter === 3) {
    // Do something every third time
    console.log("Third time's the charm!");

    // Reset counter
    counter = 0;
  }
});
<button id="button">Click Me!</button>

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

इस विकल्प पर विचार करें

var element = document.getElementById('button');

element.addEventListener("click", (function() {
  // init the count to 0
  var count = 0;

  return function(e) { // <- This function becomes the click handler
    count++; //    and will retain access to the above `count`

    if (count === 3) {
      // Do something every third time
      console.log("Third time's the charm!");

      //Reset counter
      count = 0;
    }
  };
})());
<button id="button">Click Me!</button>

कुछ बातों पर ध्यान दें।

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

एक साधारण एक लाइन बंद

//          _______________________Immediately invoked______________________
//         |                                                                |
//         |        Scope retained for use      ___Returned as the____      |
//         |       only by returned function   |    value of func     |     |
//         |             |            |        |                      |     |
//         v             v            v        v                      v     v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();

लौटाए गए फ़ंक्शन के बाहर के सभी चर लौटे फ़ंक्शन के लिए उपलब्ध हैं, लेकिन वे सीधे दिए गए फ़ंक्शन ऑब्जेक्ट के लिए उपलब्ध नहीं हैं ...

func();  // Alerts "val"
func.a;  // Undefined

उसे ले लो? तो हमारे प्राथमिक उदाहरण में, गणना चर बंद होने के भीतर निहित है और हमेशा घटना हैंडलर के लिए उपलब्ध है, इसलिए यह क्लिक से क्लिक करने के लिए अपनी स्थिति को बरकरार रखता है।

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

तुम वहाँ जाओ; अब आप इस व्यवहार को पूरी तरह से समाप्त कर रहे हैं।

पूर्ण ब्लॉग पोस्ट (jQuery के विचारों सहित)


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

40
@James भले ही आप निराश हों, उनका उदाहरण (और पूरी पोस्ट) मेरे द्वारा देखे गए सर्वश्रेष्ठ में से एक है। हालांकि यह प्रश्न पुराना नहीं है और मेरे लिए हल है, यह पूरी तरह से +1 के लायक है।
ई-सिटिज

84
"मुझे यह जानने की आवश्यकता है कि बटन को कितनी बार क्लिक किया गया है, और हर तीसरे क्लिक पर कुछ करें ..." इस पर मेरा ध्यान गया। एक उपयोग का मामला और समाधान यह दर्शाता है कि कैसे एक बंद करना इतनी रहस्यमयी बात नहीं है और हम में से बहुत से लोग उन्हें लिख रहे हैं, लेकिन आधिकारिक नाम नहीं जानते हैं।
13:22 पर क्रिस 22

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

बंद होने वाले व्यवहार के लिए +1 । हम सीमित कर सकते हैं बंद व्यवहार करने के लिए कार्य करता है जावास्क्रिप्ट में या इस अवधारणा को भी भाषा के अन्य संरचनाओं के लिए लागू किया जा सकता है?
डज़ियामिड

492

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

    var bind = function(x) {
        return function(y) { return x + y; };
    }
    
    var plus5 = bind(5);
    console.log(plus5(3));

यदि जावास्क्रिप्ट बंद नहीं हुआ तो यहां क्या होगा ? बस अंतिम विधि में कॉल को उसके विधि निकाय से बदलें (जो मूल रूप से फ़ंक्शन कॉल क्या करता है) और आपको मिलता है:

console.log(x + 3);

अब, परिभाषा कहाँ है x? हमने इसे वर्तमान दायरे में परिभाषित नहीं किया है। एकमात्र समाधान बताने के लिए है plus5 ले जाने के (या बल्कि, अपने माता-पिता की गुंजाइश) इसके दायरे के आसपास। इस तरह, xअच्छी तरह से परिभाषित है और यह मान 5 से जुड़ा है।


11
यह ठीक उसी प्रकार का उदाहरण है जो बहुत से लोगों को यह सोचने में भ्रमित करता है कि यह ऐसे मान हैं जो लौटे फ़ंक्शन में उपयोग किए जाते हैं, न कि परिवर्तनशील चर। यदि इसे "x + = y" वापस करने के लिए परिवर्तित किया गया था, या इससे बेहतर दोनों और कोई अन्य फ़ंक्शन "x * = y", तो यह स्पष्ट होगा कि कुछ भी कॉपी नहीं किया जा रहा है। फ़्रेम को स्टैक करने के लिए उपयोग किए गए लोगों के लिए, इसके बजाय हीप फ़्रेम का उपयोग करने की कल्पना करें, जो फ़ंक्शन के वापस आने के बाद भी जारी रह सकता है।
मैट

14
@ मैट मैं असहमत हूं। एक उदाहरण सभी संपत्तियों को विस्तृत रूप से दस्तावेज करने के लिए नहीं है । यह करने के लिए है reductive और एक अवधारणा की मुख्य विशेषता यह दर्शाते हैं। ओपी ने एक सरल स्पष्टीकरण ("छह साल की उम्र के लिए") मांगा। स्वीकृत उत्तर लें: यह संक्षिप्त स्पष्टीकरण देने में पूरी तरह से विफल है, ठीक है क्योंकि यह संपूर्ण होने का प्रयास करता है। (मैं आपसे सहमत हूं कि यह जावास्क्रिप्ट की एक महत्वपूर्ण संपत्ति है जो बाध्यकारी मूल्य के बजाय संदर्भ से है ... लेकिन फिर, एक सफल व्याख्या वह है जो नंगे न्यूनतम तक कम हो जाती है।)
कोनराड रूडोल्फ

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

@ मम्म हम्म, मुझे यकीन नहीं है कि मैं आपको पूरी तरह से समझता हूं लेकिन मैं यह देखना शुरू करता हूं कि आपके पास एक वैध बिंदु हो सकता है। चूंकि टिप्पणियां बहुत कम हैं, क्या आप शायद समझा सकते हैं कि आपके लिए जिस्ट / पेस्टी या चैट रूम में क्या मतलब है? धन्यवाद।
कोनराड रुडोल्फ

2
@KonradRudolph मुझे लगता है कि मैं x + = y के उद्देश्य के बारे में स्पष्ट नहीं था। उद्देश्य सिर्फ लौटे समारोह का उपयोग कर एक ही रखने के लिए है कि बार-बार कॉल दिखाने के लिए था चर (के रूप में ही करने का विरोध एक्स मूल्य है, जो लोगों की कल्पना "डाला" है, जब समारोह बनाई गई है)। यह आपके फिडल में पहले दो अलर्ट की तरह है। एक अतिरिक्त फ़ंक्शन x * = y का उद्देश्य यह दिखाना होगा कि कई लौटे फ़ंक्शन सभी समान x साझा करते हैं।
मैट

376

ठीक है, 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");


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

376

TLDR

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

विवरण

ECMAScript विनिर्देश की शब्दावली में, [[Environment]]प्रत्येक फ़ंक्शन-ऑब्जेक्ट के संदर्भ द्वारा एक क्लोजर को लागू करने के लिए कहा जा सकता है , जो उस शाब्दिक वातावरण को इंगित करता है जिसके भीतर फ़ंक्शन परिभाषित है।

जब किसी फ़ंक्शन को आंतरिक [[Call]]विधि के माध्यम से आमंत्रित किया जाता है , तो [[Environment]]फ़ंक्शन-ऑब्जेक्ट पर संदर्भ को नव-निर्मित निष्पादन संदर्भ (स्टैक फ्रेम) के पर्यावरण रिकॉर्ड के बाहरी पर्यावरण संदर्भ में कॉपी किया जाता है ।

निम्न उदाहरण में, फ़ंक्शन fवैश्विक निष्पादन संदर्भ के शाब्दिक वातावरण पर बंद हो जाता है:

function f() {}

निम्नलिखित उदाहरण में, फ़ंक्शन फ़ंक्शन hके शाब्दिक वातावरण पर बंद हो जाता है g, जो बदले में, वैश्विक निष्पादन संदर्भ के शाब्दिक वातावरण पर बंद हो जाता है।

function g() {
    function h() {}
}

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

निम्नलिखित उदाहरण में, फ़ंक्शन फ़ंक्शन jके शाब्दिक वातावरण से अधिक बंद हो जाता है i, जिसका अर्थ है कि xफ़ंक्शन फ़ंक्शन के अंदर से दिखाई देता है j, जब फ़ंक्शन iपूरा हो जाता है:

function i() {
    var x = 'mochacchino'
    return function j() {
        console.log('Printing the value of x, from within function j: ', x)
    }
} 

const k = i()
setTimeout(k, 500) // invoke k (which is j) after 500ms

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

function l() {
  var y = 'vanilla';

  return {
    setY: function(value) {
      y = value;
    },
    logY: function(value) {
      console.log('The value of y is: ', y);
    }
  }
}

const o = l()
o.logY() // The value of y is: vanilla
o.setY('chocolate')
o.logY() // The value of y is: chocolate

बाहरी वातावरण के संदर्भों के माध्यम से निष्पादन संदर्भों के बीच जुड़े हुए शाब्दिक वातावरण की श्रृंखला, एक कार्यक्षेत्र श्रृंखला बनाती है और किसी भी फ़ंक्शन से दिखाई देने वाले पहचानकर्ताओं को परिभाषित करती है।

कृपया ध्यान दें कि स्पष्टता और सटीकता में सुधार करने के प्रयास में, यह उत्तर मूल से काफी हद तक बदल दिया गया है।


56
वाह, कभी नहीं पता था कि आप इस console.logतरह से स्ट्रिंग प्रतिस्थापन का उपयोग कर सकते हैं । अगर किसी और को दिलचस्पी है तो अधिक हैं: developer.mozilla.org/en-US/docs/DOM/…
फ्लैश

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

क्लोज़र वस्तुओं और कक्षाओं आदि की तरह अधिक ध्वनि करते हैं। यकीन नहीं कि बहुत सारे लोग इन दोनों की तुलना क्यों नहीं करते हैं - हमारे लिए सीखना आसान होगा।
अल्मारुफ़

365

यह कुछ अन्य उत्तरों में दिखाई देने वाली बंदियों के बारे में कई (संभव) गलतफहमियों को दूर करने का प्रयास है।

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

15
जेम्स, मैंने कहा कि क्लोजिंग "शायद" है जो एनक्लोजिंग फ़ंक्शन के कॉल के समय बनाया गया है क्योंकि यह प्रशंसनीय है कि एक कार्यान्वयन कुछ समय बाद तक एक बंद होने के निर्माण को स्थगित कर सकता है, जब यह एक बंद का फैसला करता है, तो इसकी बिल्कुल आवश्यकता है। यदि एन्क्लोज़िंग फ़ंक्शन में कोई आंतरिक फ़ंक्शन परिभाषित नहीं है, तो किसी भी समापन की आवश्यकता नहीं होगी। तो शायद यह तब तक इंतजार कर सकता है जब तक कि पहले आंतरिक फ़ंक्शन का निर्माण न हो जाए, फिर एन्कोडिंग फ़ंक्शन के कॉल संदर्भ से बाहर एक क्लोजर बनाएं।
dlaliberte

9
@ चुकंदर-चुकंदर मान लीजिए कि हमारे पास एक आंतरिक फ़ंक्शन है जो किसी अन्य फ़ंक्शन को दिया जाता है जहां बाहरी फ़ंक्शन के वापस आने से पहले इसका उपयोग किया जाता है, और मान लीजिए कि हम बाहरी फ़ंक्शन से भी उसी आंतरिक फ़ंक्शन को वापस करते हैं। यह दोनों मामलों में समान रूप से एक ही फ़ंक्शन है, लेकिन आप कह रहे हैं कि बाहरी फ़ंक्शन वापस आने से पहले, आंतरिक फ़ंक्शन कॉल स्टैक के लिए "बाध्य" है, जबकि यह वापस आने के बाद, आंतरिक फ़ंक्शन अचानक बंद होने के लिए बाध्य है। यह दोनों मामलों में पहचान का व्यवहार करता है; शब्दार्थ समान हैं, तो क्या आप केवल कार्यान्वयन विवरण के बारे में बात नहीं कर रहे हैं?
dlaliberte

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

9
वह लेख पढ़ना मुश्किल है, लेकिन मुझे लगता है कि यह वास्तव में समर्थन करता है जो मैं कह रहा हूं। यह कहता है: "एक फ़ंक्शन फ़ंक्शन ऑब्जेक्ट को वापस करने से बनता है [...] या सीधे इस तरह के फ़ंक्शन ऑब्जेक्ट के लिए एक संदर्भ निर्दिष्ट करके, उदाहरण के लिए, एक वैश्विक चर।" मेरा मतलब यह नहीं है कि जीसी अप्रासंगिक है। बल्कि, GC के कारण, और क्योंकि आंतरिक फ़ंक्शन बाहरी फ़ंक्शन के कॉल संदर्भ (या [[स्कोप]] जैसा कि लेख कहता है) से जुड़ा हुआ है, तो इससे कोई फर्क नहीं पड़ता कि बाहरी फ़ंक्शन कॉल रिटर्न करता है क्योंकि आंतरिक के साथ बाध्यकारी फंक्शन महत्वपूर्ण चीज है।
dlaliberte

3
बहुत बढ़िया जवाब! एक बात जो आपको जोड़नी चाहिए वह यह है कि सभी फ़ंक्शन निष्पादन की पूरी सामग्री को बंद कर देते हैं जिसमें वे परिभाषित हैं। इससे कोई फर्क नहीं पड़ता कि वे माता-पिता के दायरे से कुछ या किसी भी चर को संदर्भित करते हैं: माता-पिता के दायरे के शाब्दिक वातावरण के संदर्भ को [[स्कोप]] बिना शर्त के रूप में संग्रहीत किया जाता है। इसे ECMA स्पेक में फंक्शन क्रिएशन पर सेक्शन से देखा जा सकता है।
असद सईदुद्दीन

236

मैंने क्लोजर समझाते हुए कुछ समय पहले एक ब्लॉग पोस्ट लिखी थी। यहाँ मैंने कहा है कि आप एक को क्यों चाहते हैं।

क्लोज़र एक ऐसा कार्य है जो किसी फ़ंक्शन को लगातार, निजी वेरिएबल्स - यानी वैरिएबल्स, जो केवल एक फ़ंक्शन के बारे में जानता है, जहां वह पिछली बार से जानकारी का ट्रैक रख सकता है कि इसे चलाया गया था।

इस अर्थ में, वे निजी विशेषताओं के साथ एक फ़ंक्शन को एक वस्तु की तरह काम करते हैं।

पूर्ण पोस्ट:

तो ये बंद होने वाली बातें क्या हैं?


तो क्या इस उदाहरण के साथ बंद होने के मुख्य लाभ पर जोर दिया जा सकता है? मेरा कहना है कि मेरे पास एक फ़ंक्शन ईमेल है (sendToAddress, errorString) मैं तब कह सकता था devError = emailError("devinrhode2@googmail.com", errorString)और फिर मेरे पास एक साझा emailError फ़ंक्शन का अपना कस्टम संस्करण है?
डेविन जी रोड

यह स्पष्टीकरण और (बंद होने वाली बात) के लिंक में संबंधित सही उदाहरण क्लोज़र को समझने का सबसे अच्छा तरीका है और शीर्ष पर सही होना चाहिए!
आशा है कि

215

क्लोजर सरल हैं:

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

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

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रिटर्न।

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

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

यह सब बहुत ज्यादा बंद करने के लिए है।



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

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


क्या होगा यदि आप कहते हैं: second_calculator = first_calculator (); second_calculator के बजाय = make_calculator (); ? एक ही होना चाहिए, है ना?
रोनेन फिस्टिंगर

4
@ रेनन: चूँकि first_calculatorएक ऑब्जेक्ट है (फंक्शन नहीं) तो आपको कोष्ठक का उपयोग नहीं करना चाहिए second_calculator = first_calculator;, क्योंकि यह एक असाइनमेंट है, न कि फंक्शन कॉल। आपके प्रश्न का उत्तर देने के लिए, फिर make_calculator पर केवल एक कॉल होगी, इसलिए केवल एक कैलकुलेटर ही बनेगा, और चर first_calculator और second_calculator दोनों एक ही कैलकुलेटर को संदर्भित करेंगे, इसलिए उत्तर 3, 403, 4433, 44330 होंगे।
मैट

204

मैं इसे छह साल की उम्र में कैसे समझाऊंगा:

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


200

क्या आप 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);​

प्रमाण है कि यह उदाहरण एक क्लोजर बनाता है भले ही आंतरिक फ़ंक्शन वापस नहीं आता है

* एसी # सवाल


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

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

176

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

क्लोजर सही किया:

console.log('CLOSURES DONE RIGHT');

var arr = [];

function createClosure(n) {
    return function () {
        return 'n = ' + n;
    }
}

for (var index = 0; index < 10; index++) {
    arr[index] = createClosure(index);
}

for (var index in arr) {
    console.log(arr[index]());
}
  • उपरोक्त कोड createClosure(n)में लूप के प्रत्येक पुनरावृत्ति में लगाया जाता है। ध्यान दें कि मैंने चर nको हाइलाइट करने के लिए नाम दिया है कि यह एक नया चर है जिसे नए फ़ंक्शन स्कोप में बनाया गया है और यह वैसा वैसा ही वैरिएबल नहीं है indexजो बाहरी स्कोप से जुड़ा है।

  • यह एक नया दायरा बनाता है और nउस दायरे से जुड़ा होता है; इसका मतलब है कि हमारे पास 10 अलग-अलग स्कोप हैं, प्रत्येक पुनरावृत्ति के लिए एक।

  • createClosure(n) एक ऐसा फ़ंक्शन देता है जो n को उस दायरे में लौटाता है।

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

क्लोजर गलत किया:

console.log('CLOSURES DONE WRONG');

function createClosureArray() {
    var badArr = [];

    for (var index = 0; index < 10; index++) {
        badArr[index] = function () {
            return 'n = ' + index;
        };
    }
    return badArr;
}

var badArr = createClosureArray();

for (var index in badArr) {
    console.log(badArr[index]());
}
  • उपरोक्त कोड में लूप को createClosureArray()फंक्शन के भीतर ले जाया गया था और फंक्शन अब केवल पूर्ण किए गए एरे को लौटाता है, जो पहली नज़र में अधिक सहज लगता है।

  • यह स्पष्ट नहीं हो सकता है कि चूंकि createClosureArray()लूप के प्रत्येक पुनरावृत्ति के लिए एक के बजाय इस फ़ंक्शन के लिए केवल एक गुंजाइश बनाई गई है, इसलिए इसे केवल एक बार लागू किया जाता है।

  • इस फ़ंक्शन के भीतर एक चर नाम दिया गया indexहै। लूप चलता है और वापस आने वाले सरणी में फ़ंक्शंस जोड़ता है index। ध्यान दें कि फ़ंक्शन के indexभीतर परिभाषित किया गया createClosureArrayहै जो केवल कभी एक बार आह्वान किया जाता है।

  • क्योंकि createClosureArray()फ़ंक्शन के भीतर केवल एक स्कोप था , indexकेवल उस स्कोप के भीतर एक मान के लिए बाध्य है। दूसरे शब्दों में, हर बार लूप के मूल्य में indexपरिवर्तन होता है, यह उसे उस सब कुछ के लिए बदलता है जो इसे उस दायरे में संदर्भित करता है।

  • सरणी में जोड़े गए सभी फ़ंक्शन indexपैरेंट स्कोप से SAME वैरिएबल को लौटाते हैं, जहां इसे 10 अलग-अलग स्कोपों ​​में से 10 के बजाय परिभाषित किया गया था जैसे कि पहला उदाहरण। अंतिम परिणाम यह है कि सभी 10 फ़ंक्शन समान चर से समान चर लौटाते हैं।

  • लूप समाप्त होने के बाद और indexसंशोधित किया जा रहा था अंत मूल्य 10 था, इसलिए सरणी में जोड़ा गया प्रत्येक फ़ंक्शन एकल indexचर का मान देता है जो अब 10 पर सेट है।

परिणाम

ग्राहक अधिकार
n = 0
n = 1
n = 2
n = 3
n = 4
n = 5
n = 6
n = 7
n = 8
n = 9

CLOSURES DON WRONG
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10


1
अच्छा जोड़, धन्यवाद। बस इसे और अधिक स्पष्ट करने के लिए, कोई कल्पना कर सकता है कि प्रत्येक पुनरावृत्ति के साथ "खराब" लूप में "खराब" सरणी कैसे बनाई जाती है: 1 पुनरावृत्ति: [फ़ंक्शन () {वापसी 'n =' + 0;}] 2 पुनरावृत्ति: [; function () {return 'n =' + 1;}), (function () {return 'n =' + 1;})) 3rd पुनरावृत्ति: [(function () {रिटर्न 'n =' + 2;}) , (फंक्शन () {रिटर्न 'एन =' + 2;;), (फंक्शन () {रिटर्न 'एन =' + 2;;)] इत्यादि], हर बार जब इंडेक्स वैल्यू में बदलाव होता है, तो यह सभी फंक्शन में परिलक्षित होता है। पहले से ही सरणी में जोड़ा गया।
अलेक्सई राजीव Alex

3
अंतर letको varठीक करने के लिए उपयोग करना ।
रूपम दत्ता

क्या यहाँ "बंद किया गया अधिकार" "बंद होने के अंदर बंद होने" का उदाहरण नहीं है?
टेक्निकलस्माइल

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

यदि आप परिणाम को पहले पुनरावृत्ति में सरणी में संग्रहीत करना चाहते हैं तो आप इसे इस तरह से इनलाइन कर सकते हैं arr[index] = (function (n) { return 'n = ' + n; })(index);:। लेकिन फिर आप एरे में परिणामी स्ट्रिंग को संचय करने के लिए एक फ़ंक्शन के बजाय स्टोर कर रहे हैं जो मेरे उदाहरण के बिंदु को हरा देता है।
Chev

164

बंद होने पर विकिपीडिया :

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

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

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

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

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) रखा जा सकता है और बाद में इसे क्रियान्वित किया जा सकता है , हर बार इसे लागू करने पर एक डेटाबेस फ़ंक्शन होता है। प्रत्येक उत्पन्न फ़ंक्शन का अपना छिपा हुआ डेटाबेस ऑब्जेक्ट होगा। क्लोजर का एक अन्य उपयोग उदाहरण तब होता है जब हम किसी फ़ंक्शन को वापस नहीं करते हैं, लेकिन एक ऑब्जेक्ट जिसमें विभिन्न उद्देश्यों के लिए कई फ़ंक्शन होते हैं, उनमें से प्रत्येक फ़ंक्शन में समान डेटा तक पहुंच होती है।


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

136

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

यहाँ एक उदाहरण है:

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

128

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

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

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"

बस इतना ही बताना है।


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

103

मुझे समझ नहीं आ रहा है कि उत्तर यहां इतने जटिल क्यों हैं।

यहाँ एक बंद है:

var a = 42;

function b() { return a; }

हाँ। आप शायद दिन में कई बार इसका इस्तेमाल करते हैं।


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

अब यह आपको क्या करने की अनुमति देता है और अधिक शानदार हो सकता है, अन्य उत्तर देखें।


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

1
वास्तव में जॉन ने क्या कहा। इससे पहले कि मैं अंत में बंद कर दिया मैं व्यावहारिक उदाहरण खोजने के लिए एक कठिन समय था। हां, फ्लोरीबॉन ने एक बंद किया, लेकिन मुझे अशिक्षित करने के लिए इसने मुझे कुछ भी नहीं सिखाया।
Chev

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

91

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

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

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

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

88

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


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

22
दरअसल, यह बाहरी फ़ंक्शन के पुराने मान नहीं हैं जो आंतरिक फ़ंक्शन के लिए उपलब्ध हैं, लेकिन पुराने चर , जिनमें कुछ फ़ंक्शन उन्हें बदलने में सक्षम थे, तो नए मान हो सकते हैं।
dlaliberte

86

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

// 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

82

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

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

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.");

80

क्लोजर के लेखक ने क्लोजर को बहुत अच्छी तरह से समझाया है, इस कारण की व्याख्या करते हुए कि हमें उनकी आवश्यकता क्यों है और लेक्सिकल ईन्वायरमेंट की व्याख्या करना जो क्लोजर को समझने के लिए आवश्यक है।
यहाँ सारांश है:

यदि कोई वैरिएबल एक्सेस किया जाता है तो क्या होता है, लेकिन यह स्थानीय नहीं है? जैसे यहाँ:

यहां छवि विवरण दर्ज करें

इस स्थिति में, दुभाषिया बाहरी LexicalEnvironmentवस्तु में चर पाता है ।

प्रक्रिया में दो चरण होते हैं:

  1. पहला, जब कोई फंक्शन एफ बनता है, तो वह खाली जगह में नहीं बनाया जाता है। एक वर्तमान LexicalEnvironment वस्तु है। उपरोक्त मामले में, यह विंडो है (फ़ंक्शन निर्माण के समय यह अपरिभाषित है)।

यहां छवि विवरण दर्ज करें

जब कोई फ़ंक्शन बनाया जाता है, तो उसे एक छिपी हुई संपत्ति मिलती है, जिसका नाम [[स्कोप]] होता है, जो वर्तमान लेक्सिकल एंवायरमेंट को संदर्भित करता है।

यहां छवि विवरण दर्ज करें

यदि एक चर पढ़ा जाता है, लेकिन कहीं भी नहीं पाया जा सकता है, तो एक त्रुटि उत्पन्न होती है।

निहित कार्य

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

यहां छवि विवरण दर्ज करें

तो, फंक्शन g में g, a और f की एक्सेस है।

बंद

बाहरी कार्य समाप्त होने के बाद एक नेस्टेड फ़ंक्शन जारी रह सकता है:

यहां छवि विवरण दर्ज करें

लेक्सिकल वातावरण को चिह्नित करना:

यहां छवि विवरण दर्ज करें

जैसा कि हम देखते हैं, this.sayउपयोगकर्ता ऑब्जेक्ट में एक संपत्ति है, इसलिए यह उपयोगकर्ता के पूरा होने के बाद भी जारी रहता है।

और अगर आपको याद है, जब this.sayबनाया जाता है, तो यह (प्रत्येक फ़ंक्शन के रूप में) this.say.[[Scope]]वर्तमान LexicalEnvironment को आंतरिक संदर्भ मिलता है। तो, वर्तमान उपयोगकर्ता निष्पादन की LexicalEnvironment स्मृति में रहता है। उपयोगकर्ता के सभी चर भी इसके गुण हैं, इसलिए उन्हें भी सावधानी से रखा जाता है, आमतौर पर कबाड़ के रूप में नहीं।

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

संक्षेप में:

  1. आंतरिक फ़ंक्शन बाहरी LexicalEnvironment के लिए एक संदर्भ रखता है।
  2. बाहरी फ़ंक्शन समाप्त होने पर भी आंतरिक फ़ंक्शन किसी भी समय इससे चर तक पहुंच सकता है।
  3. जब तक कोई आंतरिक फ़ंक्शन नहीं होता है, तब तक ब्राउज़र मेमोरी में उसके सभी गुणों और उसके सभी गुणों (चर) को स्मृति में रखता है।

इसे क्लोजर कहा जाता है।


78

जावास्क्रिप्ट कार्य उनके उपयोग कर सकते हैं:

  1. तर्क
  2. स्थानीय (जो उनके स्थानीय चर और स्थानीय कार्य हैं)
  3. पर्यावरण, जिसमें शामिल हैं:
    • DOM सहित ग्लोबल्स
    • बाहरी कार्यों में कुछ भी

यदि कोई फ़ंक्शन अपने वातावरण तक पहुंचता है, तो फ़ंक्शन एक क्लोजर है।

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

वैश्विक पर्यावरण का उपयोग करने वाले क्लोजर का उदाहरण:

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

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

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

इन सभी कार्यों के चारों ओर क्लोजर हैं क्योंकि वे सभी अपने पर्यावरण तक पहुंचते हैं।


59

6 साल के बच्चे के पिता के रूप में, वर्तमान में छोटे बच्चों (और कोई औपचारिक शिक्षा के लिए कोडिंग करने के लिए एक रिश्तेदार नौसिखिया है ताकि सुधार की आवश्यकता होगी), मुझे लगता है कि सबक हाथों से खेलने के माध्यम से सबसे अच्छा होगा। यदि 6 साल का बच्चा यह समझने के लिए तैयार है कि एक क्लोजर क्या है, तो वे काफी पुराने हैं कि खुद को जाना है। मेरा सुझाव है कि कोड को jsfiddle.net में पेस्ट करके, थोड़ा समझाकर, और एक अनोखे गाने को तैयार करने के लिए उन्हें अकेला छोड़ दूं। नीचे दिए गए व्याख्यात्मक पाठ शायद 10 साल की उम्र के लिए अधिक उपयुक्त हैं।

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

निर्देश

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

CODE: उपरोक्त सभी लेखन को कोड कहा जाता है । यह जावास्क्रिप्ट में लिखा है।

JAVASCRIPT: जावास्क्रिप्ट एक भाषा है। जैसे अंग्रेजी या फ्रेंच या चीनी भाषा हैं। बहुत सारी भाषाएं हैं जो कंप्यूटर और अन्य इलेक्ट्रॉनिक प्रोसेसर द्वारा समझी जाती हैं। एक कंप्यूटर द्वारा समझने के लिए जावास्क्रिप्ट के लिए एक दुभाषिया की आवश्यकता होती है। सोचिए अगर कोई शिक्षक जो केवल रूसी बोलता है, वह आपकी कक्षा को स्कूल में पढ़ाने आता है। जब शिक्षक "все садятся" कहता है, तो कक्षा समझ नहीं पाएगी। लेकिन सौभाग्य से आपकी कक्षा में एक रूसी शिष्य है जो सभी को यह बताता है कि "सब लोग बैठते हैं" - इसलिए आप सभी करते हैं। वर्ग कंप्यूटर की तरह है और रूसी शिष्य दुभाषिया है। जावास्क्रिप्ट के लिए सबसे आम दुभाषिया एक ब्राउज़र कहा जाता है।

BROWSER: जब आप किसी वेबसाइट पर जाने के लिए कंप्यूटर, टैबलेट या फोन पर इंटरनेट से कनेक्ट होते हैं, तो आप एक ब्राउजर का उपयोग करते हैं। आपके द्वारा ज्ञात उदाहरण इंटरनेट एक्सप्लोरर, क्रोम, फ़ायरफ़ॉक्स और सफारी हैं। ब्राउज़र जावास्क्रिप्ट को समझ सकता है और कंप्यूटर को बता सकता है कि उसे क्या करने की आवश्यकता है। जावास्क्रिप्ट निर्देशों को फ़ंक्शन कहा जाता है।

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

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

मुझे खरीदारी करने का समय नहीं मिला है, इसलिए निर्णय लेने के लिए फ़ंक्शन को जानना होगा कि हमारे पास फ्रिज में क्या है। प्रत्येक घटक का खाना पकाने का समय अलग-अलग होता है और हम चाहते हैं कि सब कुछ उसी समय रोबोट द्वारा गर्म परोसा जाए। हमें उस डेटा को फ़ंक्शन प्रदान करना होगा जो हमें पसंद है, फ़ंक्शन फ्रिज में 'बात' कर सकता है, और फ़ंक्शन रोबोट को नियंत्रित कर सकता है।

एक फ़ंक्शन में सामान्य रूप से एक नाम, कोष्ठक और ब्रेसिज़ होते हैं। ऐशे ही:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

ध्यान दें कि /*...*/और //ब्राउज़र द्वारा पढ़ा जा रहा कोड बंद करें।

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

PARENTHESES: "कोष्ठक" या ()फैक्ट्री में सूचना के पैकेट भेजने के लिए जावास्क्रिप्ट फंक्शन फैक्ट्री के दरवाजे या गली में एक पोस्ट बॉक्स पर लेटर बॉक्स हैं। कभी-कभी पोस्टबॉक्स को उदाहरण के लिए चिह्नित किया जा सकता है, cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime)इस स्थिति में आप जानते हैं कि आपको इसे क्या डेटा देना है।

BRACES: "ब्रेसेस" जो इस तरह दिखते हैं, {}वे हमारे कारखाने की रंगी हुई खिड़कियां हैं। कारखाने के अंदर से आप बाहर देख सकते हैं, लेकिन बाहर से आप अंदर नहीं देख सकते।

लम्बी कोड प्रदर्शनी अबोवे

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

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

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

अब, फंक्शन सिंग () के बाद , कोड के अंत के पास लाइन है

var person="an old lady";

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

अंतर्राष्ट्रीय संस्करण: व्यक्ति एक वैश्विक चर है, जिसका अर्थ है कि यदि आप "वृद्ध महिला" से इसके मूल्य को "एक युवा पुरुष" में बदलते हैं , तो व्यक्ति तब तक एक युवा व्यक्ति रहेगा जब तक आप इसे फिर से बदलने का निर्णय नहीं लेते हैं और किसी अन्य कार्य में कोड देख सकता है कि यह एक जवान आदमी है। प्रेस F12बटन या विकल्प सेटिंग पर नज़र एक ब्राउज़र के डेवलपर कंसोल खोलें और "व्यक्ति" टाइप देखने के लिए क्या यह मान है। person="a young man"इसे बदलने के लिए टाइप करें और फिर "व्यक्ति" टाइप करें फिर देखें कि यह बदल गया है।

इसके बाद हमारे पास लाइन है

sing(person);

यह रेखा फ़ंक्शन को कॉल कर रही है, जैसे कि वह एक कुत्ते को बुला रही हो

"चलो गाओ , आओ और मिल व्यक्ति !"

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

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

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

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

बंद होने के बाद लाइनें आती हैं

fly();
spider();
bird();
cat();

गायन () फ़ंक्शन इनमें से प्रत्येक फ़ंक्शन को दिए गए क्रम में कॉल करेगा। फिर गायन () फ़ंक्शन का काम किया जाएगा।


56

ठीक है, 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 है।


49

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

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

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

इसे समझाने के लिए एक और सरल तरीका है गुंजाइश के संदर्भ में:

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


49

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

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

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

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

एक उदाहरण:

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();

47

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

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

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

outerFunction();

ALERT: बंदर

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

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

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

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

ALERT: बंदर

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

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

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

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

outerFunction = null;
alert(referenceToInnerFunction());

ALERT: बंदर ALERT: बंदर

लेकिन यह कैसे है? कैसे कर सकते हैं ReferenceToInnerFunction को अभी भी बाहरी मूल्य का पता चल गया है कि बाहरी कार्य शून्य हो गया है?

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

//////////

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

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

    innerFunction();
}

outerFunction();

ALERT: गोरिल्ला

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


45

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

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


मैं सहमत हूं: उक्त मोज़िला पृष्ठ विशेष रूप से सरल और संक्षिप्त है। आश्चर्यजनक रूप से आपके पोस्ट को दूसरों की तरह व्यापक रूप से सराहना नहीं मिली है।
Brice Coustillas
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.