हर अब और फिर मुझे "क्लोजर" का उल्लेख किया जा रहा है, और मैंने इसे देखने की कोशिश की, लेकिन विकी एक स्पष्टीकरण नहीं देता है जिसे मैं समझता हूं। क्या कोई मेरी मदद कर सकता है?
हर अब और फिर मुझे "क्लोजर" का उल्लेख किया जा रहा है, और मैंने इसे देखने की कोशिश की, लेकिन विकी एक स्पष्टीकरण नहीं देता है जिसे मैं समझता हूं। क्या कोई मेरी मदद कर सकता है?
जवाबों:
(डिस्क्लेमर: यह एक बुनियादी व्याख्या है; जहाँ तक परिभाषा जाती है, मैं थोड़ा सरल कर रहा हूँ)
एक बंद करने के बारे में सोचने का सबसे सरल तरीका एक फ़ंक्शन है जिसे एक चर के रूप में संग्रहीत किया जा सकता है (जिसे "प्रथम श्रेणी के फ़ंक्शन के रूप में संदर्भित किया जाता है"), जो उस क्षेत्र में बनाए गए दायरे में अन्य चर को एक्सेस करने की विशेष क्षमता रखता है।
उदाहरण (जावास्क्रिप्ट):
var setKeyPress = function(callback) {
document.onkeypress = callback;
};
var initialize = function() {
var black = false;
document.onclick = function() {
black = !black;
document.body.style.backgroundColor = black ? "#000000" : "transparent";
}
var displayValOfBlack = function() {
alert(black);
}
setKeyPress(displayValOfBlack);
};
initialize();
कार्य 1 को सौंपा गया है document.onclick
और displayValOfBlack
बंद हैं। आप देख सकते हैं कि वे दोनों बूलियन चर का संदर्भ देते हैं black
, लेकिन यह चर फ़ंक्शन के बाहर सौंपा गया है। क्योंकि black
है गुंजाइश जहां समारोह परिभाषित किया गया था करने के लिए स्थानीय , इस चर के लिए सूचक संरक्षित है।
यदि आप इसे HTML पृष्ठ में रखते हैं:
यह दर्शाता है कि दोनों की पहुंच समान है black
, और इसका उपयोग बिना किसी आवरण वस्तु के राज्य को संग्रहीत करने के लिए किया जा सकता है ।
कॉल यह setKeyPress
है कि किसी चर की तरह किसी फ़ंक्शन को कैसे प्रदर्शित किया जा सकता है। गुंजाइश बंद में संरक्षित अभी भी एक जहां समारोह में परिभाषित किया गया है।
क्लोजर आमतौर पर ईवेंट हैंडलर के रूप में उपयोग किया जाता है, विशेष रूप से जावास्क्रिप्ट और एक्शनस्क्रिप्ट में। क्लोज़र का अच्छा उपयोग आपको ऑब्जेक्ट रैपर बनाने के बिना हैंडलर को इवेंट करने के लिए वैरिएबल बाइंड करने में मदद करेगा। हालांकि, लापरवाह उपयोग से मेमोरी लीक हो जाएगी (जैसे कि जब एक अप्रयुक्त लेकिन संरक्षित ईवेंट हैंडलर स्मृति में बड़ी वस्तुओं को रखने के लिए एकमात्र चीज हो, विशेष रूप से डोम ऑब्जेक्ट्स, कचरा संग्रह को रोकना)।
1: वास्तव में, जावास्क्रिप्ट में सभी फ़ंक्शन क्लोजर हैं।
black
एक फ़ंक्शन के अंदर घोषित किया गया है, इसलिए क्या यह स्टैक अनइंड्स के रूप में नष्ट नहीं होगा ...?
black
से एक समारोह के अंदर घोषित किया जाता है, तब तक वह नष्ट नहीं होगा"। यह भी याद रखें कि यदि आप किसी फ़ंक्शन में किसी ऑब्जेक्ट की घोषणा करते हैं और फिर उसे एक ऐसे वेरिएबल को असाइन करते हैं जो कहीं और रहता है, तो वह ऑब्जेक्ट संरक्षित है क्योंकि इसके अन्य संदर्भ हैं।
एक बंद मूल रूप से एक वस्तु को देखने का एक अलग तरीका है। ऑब्जेक्ट एक डेटा है जिसमें एक या एक से अधिक फ़ंक्शंस होते हैं। क्लोजर एक ऐसा फंक्शन है जिसमें एक या एक से अधिक वैरिएबल होते हैं। दो मूल रूप से समान हैं, कम से कम कार्यान्वयन स्तर पर। असली अंतर यह है कि वे कहां से आते हैं।
ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, आप अपने सदस्य चर और उसके तरीकों (सदस्य फ़ंक्शन) को अप-फ्रंट पर परिभाषित करके ऑब्जेक्ट क्लास घोषित करते हैं, और फिर आप उस क्लास के उदाहरण बनाते हैं। प्रत्येक उदाहरण निर्माणकर्ता द्वारा आरंभ किए गए सदस्य डेटा की एक प्रति के साथ आता है। फिर आपके पास एक ऑब्जेक्ट प्रकार का एक चर है, और इसे डेटा के एक टुकड़े के रूप में चारों ओर से गुजारें, क्योंकि फोकस इसकी प्रकृति पर डेटा के रूप में है।
एक बंद में, दूसरी तरफ, ऑब्जेक्ट को ऑब्जेक्ट क्लास की तरह ऊपर-सामने परिभाषित नहीं किया जाता है, या आपके कोड में एक कंस्ट्रक्टर कॉल के माध्यम से त्वरित किया जाता है। इसके बजाय, आप किसी अन्य फ़ंक्शन के अंदर क्लोजर को फ़ंक्शन के रूप में लिखते हैं। क्लोजर बाहरी फ़ंक्शन के किसी भी स्थानीय चर को संदर्भित कर सकता है, और कंपाइलर पता लगाता है और इन चर को बाहरी फ़ंक्शन के स्टैक स्पेस से क्लोजर के छिपे हुए ऑब्जेक्ट घोषणा में स्थानांतरित करता है। आपके पास एक क्लोजर प्रकार का एक चर है, और भले ही यह मूल रूप से हुड के तहत एक वस्तु है, आप इसे फ़ंक्शन संदर्भ के रूप में चारों ओर से गुजरते हैं, क्योंकि फ़ोकस एक फ़ंक्शन के रूप में इसकी प्रकृति पर है।
क्लोजर शब्द इस तथ्य से आता है कि कोड का एक टुकड़ा (ब्लॉक, फंक्शन) मुक्त वैरिएबल हो सकता है जो बंद हो जाता है (यानी एक मूल्य के लिए बाध्य) पर्यावरण द्वारा जिसमें कोड के ब्लॉक को परिभाषित किया गया है।
उदाहरण के लिए स्कैला फ़ंक्शन परिभाषा लें:
def addConstant(v: Int): Int = v + k
फ़ंक्शन बॉडी में दो नाम (चर) होते हैं v
और k
दो पूर्णांक मानों का संकेत देते हैं। नाम v
बाध्य है क्योंकि यह फ़ंक्शन के एक तर्क के रूप में घोषित किया गया है addConstant
(फ़ंक्शन घोषणा को देखकर हम जानते हैं कि v
फ़ंक्शन को लागू किए जाने पर एक मान असाइन किया जाएगा)। नाम k
नि: शुल्क wrt फ़ंक्शन है addConstant
क्योंकि फ़ंक्शन में कोई सुराग नहीं है कि मूल्य क्या k
(और कैसे) से जुड़ा हुआ है।
कॉल का मूल्यांकन करने के लिए जैसे:
val n = addConstant(10)
हमें k
एक मान निर्दिष्ट करना होगा, जो केवल तभी हो सकता है जब नाम k
उस संदर्भ में परिभाषित किया गया हो जिसमें addConstant
परिभाषित किया गया हो। उदाहरण के लिए:
def increaseAll(values: List[Int]): List[Int] =
{
val k = 2
def addConstant(v: Int): Int = v + k
values.map(addConstant)
}
अब जबकि हमने addConstant
एक संदर्भ में परिभाषित किया है जहां k
परिभाषित addConstant
किया गया है, एक बंद हो गया है क्योंकि इसके सभी मुक्त चर अब बंद हो गए हैं (एक मूल्य के लिए): addConstant
इसे लागू किया जा सकता है और चारों ओर पारित किया जा सकता है जैसे कि यह एक फ़ंक्शन था। नोट करें कि नि: शुल्क चर k
एक मूल्य के लिए बाध्य है जब बंद को परिभाषित किया गया है , जबकि तर्क चर v
बाध्य है जब बंद किया जाता है ।
इसलिए एक बंद मूल रूप से एक फ़ंक्शन या कोड ब्लॉक है जो गैर-स्थानीय मूल्यों को संदर्भ के द्वारा बाध्य किए जाने के बाद अपने मुक्त चर के माध्यम से उपयोग कर सकता है।
कई भाषाओं में, यदि आप एक बंद का उपयोग केवल एक बार करते हैं तो आप इसे गुमनाम कर सकते हैं , जैसे
def increaseAll(values: List[Int]): List[Int] =
{
val k = 2
values.map(v => v + k)
}
ध्यान दें कि बिना फ्री चर के साथ एक फ़ंक्शन बंद होने का एक विशेष मामला है (मुक्त चर के खाली सेट के साथ)। अनागत रूप से, एक अनाम फ़ंक्शन एक अनाम क्लोजर का एक विशेष मामला है , अर्थात एक अनाम फ़ंक्शन एक अनाम क्लोजर है जिसमें कोई मुक्त चर नहीं है।
जावास्क्रिप्ट में एक सरल विवरण:
var closure_example = function() {
var closure = 0;
// after first iteration the value will not be erased from the memory
// because it is bound with the returned alertValue function.
return {
alertValue : function() {
closure++;
alert(closure);
}
};
};
closure_example();
alert(closure)
पहले निर्मित मान का उपयोग करेगा closure
। लौटाया गया alertValue
फ़ंक्शन नामस्थान उस नामस्थान से कनेक्ट किया जाएगा जिसमें closure
चर रहता है। जब आप पूरे फ़ंक्शन को हटाते हैं, तो closure
चर का मूल्य हटा दिया जाएगा, लेकिन तब तक, alertValue
फ़ंक्शन हमेशा चर के मूल्य को पढ़ने / लिखने में सक्षम होगा closure
।
यदि आप इस कोड को चलाते हैं, तो पहला पुनरावृत्ति closure
वैरिएबल को 0 मान देगा और फ़ंक्शन को फिर से लिखेगा:
var closure_example = function(){
alertValue : function(){
closure++;
alert(closure);
}
}
और क्योंकि फ़ंक्शन को निष्पादित alertValue
करने के लिए स्थानीय चर की आवश्यकता closure
होती है, यह पहले से निर्दिष्ट स्थानीय चर के मूल्य के साथ खुद को बांधता है closure
।
और अब हर बार जब आप closure_example
फ़ंक्शन को कॉल करते हैं, तो यह closure
वेरिएबल के बढ़े हुए मूल्य को लिख देगा क्योंकि alert(closure)
यह बाध्य है।
closure_example.alertValue()//alerts value 1
closure_example.alertValue()//alerts value 2
closure_example.alertValue()//alerts value 3
//etc.
एक "क्लोजर", संक्षेप में, कुछ स्थानीय स्थिति और कुछ कोड, एक पैकेज में संयुक्त है। आमतौर पर, स्थानीय राज्य एक आस-पास (लेक्सिकल) दायरे से आता है और कोड (अनिवार्य रूप से) एक आंतरिक कार्य है जो फिर बाहर की ओर लौटाया जाता है। क्लोजर तब कैप्चर किए गए वेरिएबल्स का एक संयोजन होता है जिसे आंतरिक फ़ंक्शन देखता है और आंतरिक फ़ंक्शन का कोड।
यह उन चीजों में से एक है, जो दुर्भाग्य से, अपरिचित होने के कारण समझाने में थोड़ा कठिन है।
अतीत में सफलतापूर्वक इस्तेमाल की गई एक सादृश्य था "कल्पना कीजिए कि हमारे पास कुछ है जिसे हम 'पुस्तक' कहते हैं, कक्ष-बंदी में, 'पुस्तक' वह है जो वहां कॉपी है, टीएओसीपी के कोने में, लेकिन टेबल-क्लोजर पर , यह एक ड्रेसडेन फाइल्स बुक की कॉपी है। इसलिए आप किस क्लोजर में हैं, इस पर निर्भर करते हुए कोड 'मुझे अलग-अलग चीजों में होने वाले परिणाम' देता है। "
static
स्थानीय चर वाले C फ़ंक्शन को बंद माना जा सकता है? क्या हास्केल में बंद होने की स्थिति है?
static
स्थानीय चर के साथ, आपके पास बिल्कुल एक है)।
यह परिभाषित करना कठिन है कि 'राज्य' की अवधारणा को परिभाषित किए बिना क्या बंद हो सकता है।
मूल रूप से, पूर्ण लेक्सिकल स्कूपिंग वाली भाषा में जो प्रथम श्रेणी के मूल्यों के रूप में कार्य करता है, कुछ विशेष होता है। अगर मुझे कुछ ऐसा करना था:
function foo(x)
return x
end
x = foo
चर x
न केवल संदर्भ देता है, function foo()
बल्कि यह भी संदर्भित करता है कि राज्य foo
पिछली बार जब वापस लौटा था। असली जादू तब होता है जब foo
अन्य कार्य इसके दायरे में आगे परिभाषित होते हैं; यह अपने स्वयं के मिनी-पर्यावरण की तरह है (बस 'सामान्य रूप से' हम वैश्विक वातावरण में कार्यों को परिभाषित करते हैं)।
कार्यात्मक रूप से यह C ++ (C?) के 'स्थिर' कीवर्ड के समान कई समस्याओं को हल कर सकता है, जो कई फ़ंक्शन कॉल में स्थानीय चर की स्थिति को बनाए रखता है; हालाँकि यह एक फ़ंक्शन में उसी सिद्धांत (स्थिर चर) को लागू करने की तरह है, क्योंकि फ़ंक्शन प्रथम श्रेणी के मान हैं; क्लोजर पूरे फ़ंक्शन की स्थिति को सहेजे जाने के लिए समर्थन जोड़ता है (C ++ के स्थैतिक कार्यों के साथ कुछ नहीं करना है)।
प्रथम श्रेणी के मूल्यों के रूप में कार्य करने और बंद करने के लिए समर्थन जोड़ने का मतलब यह भी है कि आपके पास मेमोरी में समान फ़ंक्शन (कक्षाओं के समान) के एक से अधिक उदाहरण हो सकते हैं। इसका मतलब यह है कि आप फ़ंक्शन की स्थिति को रीसेट किए बिना उसी कोड का फिर से उपयोग कर सकते हैं, जैसा कि किसी फ़ंक्शन के अंदर C ++ स्थिर चर के साथ काम करते समय आवश्यक है (इस बारे में गलत हो सकता है?)।
यहाँ लुआ के बंद समर्थन का कुछ परीक्षण किया गया है।
--Closure testing
--By Trae Barlow
--
function myclosure()
print(pvalue)--nil
local pvalue = pvalue or 10
return function()
pvalue = pvalue + 10 --20, 31, 42, 53(53 never printed)
print(pvalue)
pvalue = pvalue + 1 --21, 32, 43(pvalue state saved through multiple calls)
return pvalue
end
end
x = myclosure() --x now references anonymous function inside myclosure()
x()--nil, 20
x() --21, 31
x() --32, 42
--43, 53 -- if we iterated x() again
परिणाम:
nil
20
31
42
यह मुश्किल हो सकता है, और यह संभवतः भाषा से भाषा में भिन्न होता है, लेकिन लू में ऐसा लगता है कि जब भी किसी फ़ंक्शन को निष्पादित किया जाता है, तो इसकी स्थिति रीसेट हो जाती है। मैं यह कहता हूं क्योंकि ऊपर दिए गए कोड से परिणाम अलग-अलग होंगे यदि हम myclosure
सीधे फ़ंक्शन / स्थिति तक पहुंच रहे थे (इसके बजाय अनाम फ़ंक्शन के माध्यम से यह वापस लौटता है), जैसा pvalue
कि 10 पर वापस रीसेट किया जाएगा; लेकिन अगर हम एक्स (अनाम फ़ंक्शन) के माध्यम से माइक्लोजर की स्थिति तक पहुंचते हैं, तो आप देख सकते हैं कि pvalue
जीवित है और स्मृति में कहीं अच्छी तरह से है। मुझे संदेह है कि इसके लिए थोड़ा और अधिक है, शायद कोई कार्यान्वयन की प्रकृति को बेहतर ढंग से समझा सकता है।
पुनश्च: मैं C ++ 11 (पिछले संस्करणों में क्या है के अलावा) की एक चाट पता नहीं है तो ध्यान दें कि यह C ++ 11 और Lua में बंद होने के बीच तुलना नहीं है। इसके अलावा, Lua से C ++ तक खींची गई सभी 'लाइनें' समानताएं हैं क्योंकि स्थिर चर और क्लोजर 100% समान नहीं हैं; भले ही वे कभी-कभी समान समस्याओं को हल करने के लिए उपयोग किए जाते हैं।
जो चीज़ मुझे निश्चित नहीं है, वह ऊपर दिए गए कोड उदाहरण में है, क्या अनाम फ़ंक्शन या उच्च क्रम फ़ंक्शन को बंद माना जाता है?
एक क्लोजर एक फ़ंक्शन है जिसमें संबंधित स्थिति होती है:
पर्ल में आप इस तरह से क्लोजर बनाते हैं:
#!/usr/bin/perl
# This function creates a closure.
sub getHelloPrint
{
# Bind state for the function we are returning.
my ($first) = @_;a
# The function returned will have access to the variable $first
return sub { my ($second) = @_; print "$first $second\n"; };
}
my $hw = getHelloPrint("Hello");
my $gw = getHelloPrint("Goodby");
&$hw("World"); // Print Hello World
&$gw("World"); // PRint Goodby World
यदि हम C ++ के साथ प्रदान की गई नई कार्यक्षमता को देखते हैं।
यह आपको वर्तमान स्थिति को ऑब्जेक्ट में बाँधने की अनुमति देता है:
#include <string>
#include <iostream>
#include <functional>
std::function<void(std::string const&)> getLambda(std::string const& first)
{
// Here we bind `first` to the function
// The second parameter will be passed when we call the function
return [first](std::string const& second) -> void
{ std::cout << first << " " << second << "\n";
};
}
int main(int argc, char* argv[])
{
auto hw = getLambda("Hello");
auto gw = getLambda("GoodBye");
hw("World");
gw("World");
}
आइए एक साधारण कार्य पर विचार करें:
function f1(x) {
// ... something
}
इस फ़ंक्शन को एक शीर्ष-स्तरीय फ़ंक्शन कहा जाता है क्योंकि यह किसी अन्य फ़ंक्शन के भीतर नेस्टेड नहीं है। प्रत्येक जावास्क्रिप्ट फ़ंक्शन अपने आप में वस्तुओं की एक सूची को "स्कोप चेन" कहा जाता है । यह स्कोप चेन ऑब्जेक्ट्स की एक ऑर्डर की गई सूची है। इनमें से प्रत्येक वस्तु कुछ चर को परिभाषित करती है।
शीर्ष-स्तरीय कार्यों में, स्कोप श्रृंखला में एक एकल ऑब्जेक्ट, वैश्विक ऑब्जेक्ट होता है। उदाहरण के लिए, f1
ऊपर दिए गए फ़ंक्शन में एक गुंजाइश श्रृंखला है जिसमें एक एकल ऑब्जेक्ट है जो सभी वैश्विक चर को परिभाषित करता है। (ध्यान दें कि यहां "ऑब्जेक्ट" शब्द का अर्थ जावास्क्रिप्ट ऑब्जेक्ट नहीं है, यह सिर्फ एक कार्यान्वयन परिभाषित वस्तु है जो एक चर कंटेनर के रूप में कार्य करता है, जिसमें जावास्क्रिप्ट "चर" देख सकता है।)
जब इस फ़ंक्शन को लागू किया जाता है, तो जावास्क्रिप्ट एक "एक्टिवेशन ऑब्जेक्ट" नामक कुछ बनाता है , और इसे गुंजाइश श्रृंखला के शीर्ष पर रखता है। इस ऑब्जेक्ट में सभी स्थानीय चर शामिल हैं (उदाहरण के लिए x
यहां)। इसलिए अब हमारे पास गुंजाइश श्रृंखला में दो ऑब्जेक्ट हैं: पहला सक्रियण ऑब्जेक्ट है और इसके नीचे वैश्विक ऑब्जेक्ट है।
ध्यान से देखें कि दोनों वस्तुओं को अलग-अलग समय पर स्कोप चेन में डाल दिया जाता है। फ़ंक्शन को परिभाषित करने पर वैश्विक ऑब्जेक्ट डाल दिया जाता है (यानी, जब जावास्क्रिप्ट ने फ़ंक्शन को पार्स किया और फ़ंक्शन ऑब्जेक्ट बनाया), और सक्रियण ऑब्जेक्ट तब फ़ंक्शन में प्रवेश किया जाता है।
तो, हम अब यह जानते हैं:
स्थिति तब दिलचस्प हो जाती है जब हम नेस्टेड कार्यों से निपटते हैं। तो, चलो एक बनाएँ:
function f1(x) {
function f2(y) {
// ... something
}
}
जब f1
हम परिभाषित होते हैं तो हमें इसके लिए एक गुंजाइश श्रृंखला मिलती है जिसमें केवल वैश्विक वस्तु होती है।
अब जब f1
कॉल किया जाता है, f1
तो सक्रियण ऑब्जेक्ट को प्राप्त करने की गुंजाइश श्रृंखला होती है। इस सक्रियण ऑब्जेक्ट में चर x
और चर है f2
जो एक फ़ंक्शन है। और, ध्यान दें कि f2
परिभाषित हो रहा है। इसलिए, इस बिंदु पर, जावास्क्रिप्ट भी एक नई गुंजाइश श्रृंखला बचाता है f2
। इस आंतरिक फ़ंक्शन के लिए सहेजी गई कार्यक्षेत्र श्रृंखला प्रभाव में वर्तमान गुंजाइश श्रृंखला है। प्रभाव में मौजूदा गुंजाइश श्रृंखला है f1
। इसलिए f2
की गुंजाइश श्रृंखला है f1
s ' वर्तमान जो की सक्रियता वस्तु शामिल हैं - गुंजाइश श्रृंखला f1
और वैश्विक वस्तु।
जब f2
इसे कहा जाता है, तो यह अपनी सक्रियता वाली वस्तु हो जाती है y
, इसकी स्कोप श्रृंखला में जोड़ दी जाती है जिसमें पहले से ही सक्रिय वस्तु f1
और वैश्विक वस्तु शामिल होती है।
यदि कोई अन्य नेस्टेड फ़ंक्शन के भीतर परिभाषित किया गया था f2
, तो इसकी गुंजाइश श्रृंखला में परिभाषा समय पर तीन ऑब्जेक्ट होंगे (दो बाहरी कार्यों के सक्रियण ऑब्जेक्ट, और वैश्विक ऑब्जेक्ट), और 4 आह्वान के समय।
तो, अब हम समझते हैं कि स्कोप चेन कैसे काम करती है लेकिन हमने अभी तक क्लोजर के बारे में बात नहीं की है।
फ़ंक्शन ऑब्जेक्ट और एक स्कोप (वैरिएबल बाइंडिंग का एक सेट) का संयोजन जिसमें फ़ंक्शन के वेरिएबल्स को हल किया जाता है, कंप्यूटर साइंस साहित्य में एक क्लोजर कहा जाता है - डेविड फ्लैनगन द्वारा निश्चित गाइड जावास्क्रिप्ट
अधिकांश फ़ंक्शंस उसी स्कोप चेन का उपयोग करके लागू किए जाते हैं जो फ़ंक्शन को परिभाषित करते समय प्रभाव में थे, और यह वास्तव में कोई फर्क नहीं पड़ता है कि एक क्लोजर शामिल है। क्लोज़र दिलचस्प हो जाते हैं जब उन्हें एक अलग स्कोप चेन के तहत लागू किया जाता है जो कि परिभाषित होने पर प्रभावी था। यह आमतौर पर तब होता है जब किसी नेस्टेड फ़ंक्शन ऑब्जेक्ट को उस फ़ंक्शन से वापस किया जाता है जिसके भीतर इसे परिभाषित किया गया था।
जब फ़ंक्शन वापस आता है, तो उस सक्रियण ऑब्जेक्ट को कार्यक्षेत्र श्रृंखला से हटा दिया जाता है। यदि कोई नेस्टेड फ़ंक्शन नहीं थे, तो सक्रियण ऑब्जेक्ट के लिए अधिक संदर्भ नहीं हैं और यह कचरा एकत्र करता है। यदि वहाँ नेस्टेड फ़ंक्शन परिभाषित किए गए थे, तो उन कार्यों में से प्रत्येक में स्कोप चेन का संदर्भ है, और यह स्कोप चेन सक्रियण ऑब्जेक्ट को संदर्भित करता है।
यदि उन नेस्टेड फ़ंक्शंस ऑब्जेक्ट्स अपने बाहरी फ़ंक्शन के भीतर बने रहे, तो, फिर वे स्वयं कचरा एकत्र करेंगे, साथ ही उनके द्वारा संदर्भित सक्रियण ऑब्जेक्ट के साथ। लेकिन यदि फ़ंक्शन एक नेस्टेड फ़ंक्शन को परिभाषित करता है और इसे वापस करता है या इसे कहीं संपत्ति में संग्रहीत करता है, तो नोड फ़ंक्शन के लिए एक बाहरी संदर्भ होगा। यह कचरा एकत्र नहीं किया जाएगा, और सक्रियण ऑब्जेक्ट जो इसे संदर्भित करता है वह कचरा एकत्र नहीं किया जाएगा।
हमारे उपरोक्त उदाहरण में, हम वहां f2
से नहीं लौटते हैं f1
, इसलिए, जब कोई कॉल f1
लौटाता है, तो उसके सक्रियण ऑब्जेक्ट को उसके स्कोप चेन और एकत्रित कचरा से हटा दिया जाएगा। लेकिन अगर हमारे पास ऐसा कुछ था:
function f1(x) {
function f2(y) {
// ... something
}
return f2;
}
यहां, लौटने f2
पर एक स्कोप चेन होगी जिसमें सक्रियण ऑब्जेक्ट होगा f1
, और इसलिए यह कचरा एकत्र नहीं किया जाएगा। इस बिंदु पर, यदि हम कॉल करते हैं f2
, तो यह f1
's' वेरिएबल x
तक पहुँचने में सक्षम होगा, जबकि हम बाहर हैं f1
।
इसलिए हम देख सकते हैं कि एक फ़ंक्शन इसके साथ गुंजाइश श्रृंखला रखता है और गुंजाइश श्रृंखला के साथ बाहरी कार्यों के सभी सक्रियण ऑब्जेक्ट आते हैं। यह बंद करने का सार है। हम कहते हैं कि जावास्क्रिप्ट में कार्य "lexically scoped" हैं , जिसका अर्थ है कि वे उस दायरे को बचाते हैं जो तब सक्रिय था जब उन्हें उस दायरे के विपरीत परिभाषित किया गया था जो सक्रिय होने पर उन्हें बुलाया गया था।
कई शक्तिशाली प्रोग्रामिंग तकनीकें शामिल हैं जिनमें निजी चर, घटना संचालित प्रोग्रामिंग, आंशिक अनुप्रयोग आदि जैसे बंद शामिल हैं ।
यह भी ध्यान दें कि यह सब उन सभी भाषाओं पर लागू होता है जो क्लोजर का समर्थन करती हैं। उदाहरण के लिए PHP (5.3+), पायथन, रूबी, आदि।
एक क्लोजर एक कंपाइलर ऑप्टिमाइज़ेशन (उर्फ सिंथैटिक शुगर?) है। कुछ लोगों ने इसे गरीब आदमी की वस्तु भी कहा है।
एरिक लिपर्ट द्वारा उत्तर देखें : (नीचे अंश)
संकलक इस तरह कोड उत्पन्न करेगा:
private class Locals
{
public int count;
public void Anonymous()
{
this.count++;
}
}
public Action Counter()
{
Locals locals = new Locals();
locals.count = 0;
Action counter = new Action(locals.Anonymous);
return counter;
}
सही बात?
साथ ही, आपने तुलना करने के लिए कहा। VB और JScript दोनों एक ही तरह से क्लोजर बनाते हैं।