जावास्क्रिप्ट में एक बंद करने के लिए एक व्यावहारिक उपयोग क्या है?


279

मैं जावास्क्रिप्ट क्लोजर के चारों ओर अपना सिर लपेटने के लिए अपनी सबसे कठिन कोशिश कर रहा हूं ।

मुझे लगता है कि एक आंतरिक फ़ंक्शन को वापस करने से, इसके तत्काल माता-पिता में परिभाषित किसी भी चर तक पहुंच होगी।

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

क्या कोई मुझे बंद करने की वास्तविक दुनिया दिखा सकता है?

यह एक है, उदाहरण के लिए?

var warnUser = function (msg) {
    var calledCount = 0;
    return function() {
       calledCount++;
       alert(msg + '\nYou have been warned ' + calledCount + ' times.');
    };
};

var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();

17
अपने कठिन प्रयास करने के लिए +1 :-) क्लोज़र के साथ शुरू करने के लिए वास्तव में कठिन लग सकता है, मुझे पता है कि वे मेरे लिए थे। एक बार जब आप उनमें से हैंग हो जाते हैं, तो आप तुरंत एक बेहतर कोडर बन जाएंगे।
एंडी ई

7
मैंने अभी जावास्क्रिप्ट में क्लोज़र के बारे में एक ब्लॉग पोस्ट लिखा है जिसमें आपको हेलफुल मिल सकता है।
Skilldrick

@Skilldrick। लिंक मर चुका है ... और मुझे यह व्यावहारिक उदाहरण बहुत मददगार लगा। youtube.com/watch?v=w1s9PgtEoJs
अबी

जवाबों:


240

मैंने चीजों को करने के लिए क्लोजर का उपयोग किया है:

a = (function () {
    var privatefunction = function () {
        alert('hello');
    }

    return {
        publicfunction : function () {
            privatefunction();
        }
    }
})();

जैसा कि आप वहां देख सकते हैं, aअब एक ऑब्जेक्ट है, जिसमें एक विधि publicfunction( a.publicfunction()) है जो कॉल करती है privatefunction, जो केवल क्लोजर के अंदर मौजूद है। आप सीधे (यानी ) कॉल नहीं कर सकते , बस ।privatefunctiona.privatefunction()publicfunction()

इसका एक न्यूनतम उदाहरण है लेकिन शायद आप इसका उपयोग कर सकते हैं? हमने इसका इस्तेमाल सार्वजनिक / निजी तरीकों को लागू करने के लिए किया।


26
आह, अगर यह एक बंद है, तो मैंने इसे जानने के बिना क्लोजर का उपयोग किया है! मैं अक्सर उस तरह से दूसरे के अंदर कार्य करता हूं, और फिर किसी भी वस्तु को सार्वजनिक करता हूं जो आपके उदाहरण की तरह एक वस्तु शाब्दिक वापस करके सार्वजनिक करता है।
एलेक्स

1
हां, जैसा कि आप देखते हैं, आप फ़ंक्शन का संदर्भ रखते हैं क्योंकि आप जिस ऑब्जेक्ट को उसके अंदर संदर्भ चर (और फ़ंक्शन) वापस करते हैं। तो आप उनका उपयोग कर रहे हैं, आप बस यह नहीं जानते थे।
फ्रांसिस्को सूटो

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

9
मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन मेरे लिए यह अभी भी पर्याप्त उत्तर प्रदान नहीं करता है। सीधे फ़ंक्शन को कॉल क्यों नहीं किया जाता है? आपको एक निजी फ़ंक्शन की आवश्यकता क्यों है?
कोडीनिजा

5
क्योंकि भले ही उदाहरण में केवल एक फ़ंक्शन है, लेकिन इसमें ऐसे चर भी हो सकते हैं जो बाहर से सुलभ नहीं हैं । कहो: var obj = (function () {var value = 0; return {get: function () {return value;}, सेट: function (val) {value = val;}}}) (); obj.set (20); obj.get (); => 20 आदि
फ्रांसिस्को सोतो

211

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

<button onclick="updateClickCount()">click me</button>  

अब कई दृष्टिकोण हो सकते हैं जैसे:

1) आप एक वैश्विक चर और काउंटर बढ़ाने के लिए एक फ़ंक्शन का उपयोग कर सकते हैं :

var counter = 0;

function updateClickCount() {
    ++counter;
    // do something with counter
}

लेकिन, नुकसान यह है कि पृष्ठ पर कोई भी स्क्रिप्ट बिना कॉल किए, काउंटर को बदल सकती हैupdateClickCount()


2) अब, आप फंक्शन के अंदर वेरिएबल को घोषित करने की सोच रहे होंगे:

function updateClickCount() {
    var counter = 0;
    ++counter;
    // do something with counter
}

लेकिन नमसते! हर बार updateClickCount()फ़ंक्शन को कॉल किया जाता है, काउंटर को फिर से 1 पर सेट किया जाता है।


3) नेस्टेड फ़ंक्शन के बारे में सोचना ?

नेस्टेड फ़ंक्शंस के पास "ऊपर" के दायरे तक पहुंच है।
इस उदाहरण में, आंतरिक फ़ंक्शन updateClickCount()की पैरेंट फ़ंक्शन में काउंटर चर तक पहुंच हैcountWrapper()

function countWrapper() {
    var counter = 0;
    function updateClickCount() {
    ++counter;
    // do something with counter
    }
    updateClickCount();    
    return counter; 
}

यह काउंटर दुविधा को हल कर सकता है, यदि आप updateClickCount()बाहर से फ़ंक्शन तक पहुंच सकते हैं और आपको counter = 0केवल एक बार निष्पादित करने का एक तरीका खोजने की आवश्यकता है, न कि हर बार।


4) बचाव के लिए बंद! (स्व-आहरण समारोह) :

 var updateClickCount=(function(){
    var counter=0;

    return function(){
     ++counter;
     // do something with counter
    }
})();

सेल्फ-इनवोकेशन फंक्शन केवल एक बार चलता है। यह counterशून्य (0) पर सेट होता है, और फ़ंक्शन एक्सप्रेशन देता है।

यह तरीका updateClickCountएक फंक्शन बन जाता है। "अद्भुत" हिस्सा यह है कि यह अभिभावक के दायरे में काउंटर तक पहुंच सकता है।

इसे जावास्क्रिप्ट क्लोजर कहा जाता है । यह एक फ़ंक्शन के लिए " निजी " चर रखना संभव बनाता है ।

counterगुमनाम समारोह के दायरे द्वारा सुरक्षित है, और केवल ऐड फंक्शन का उपयोग करके बदला जा सकता है!

क्लोजर पर अधिक जीवंत उदाहरण:

<script>
        var updateClickCount=(function(){
    	var counter=0;
    
    	return function(){
    	++counter;
    	 document.getElementById("spnCount").innerHTML=counter;
    	}
      })();
    </script>

    <html>
	 <button onclick="updateClickCount()">click me</button>
	  <div> you've clicked 
		<span id="spnCount"> 0 </span> times!
	 </div>
    </html>


संदर्भ: https://www.w3schools.com/js/js_function_closures.asp


50
यह पहला जवाब यह है कि बनाया मुझे कहना है "ओह, कि मैं क्यों बंद का प्रयोग करेंगे!"
डेविल्स एडवोकेट

6
u ने मेरा दिन बनाया :)
जैरीगोपाल

15
मैं बस w3schools पृष्ठ को बंद होने पर पढ़ता हूं और फिर अधिक जानकारी के लिए यहां आया हूं। यह w3schools पृष्ठ के समान है: w3schools.com/js/js_function_closures.asp
tyelford

1
@ JerryGoyal क्या आप इसे 2 अलग-अलग बटन से काम कर सकते हैं? मैं यह पता नहीं लगा सकता कि 2 चर (फ़ंक्शन की प्रतियां) का सहारा लिए बिना, जो मुख्य लाभ / सुविधा में से कुछ को दूर करने के लिए लगता है।
टायलर कोलियर

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

69

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

  1. एक एल्गोरिथ्म (क्लासिक उच्च-क्रम प्रोग्रामिंग) में पैरामीटर किए गए व्यवहार को पास करना:

    function proximity_sort(arr, midpoint) {
        arr.sort(function(a, b) { a -= midpoint; b -= midpoint; return a*a - b*b; });
    }
  2. वस्तु उन्मुख प्रोग्रामिंग अनुकरण:

    function counter() {
        var a = 0;
        return {
            inc: function() { ++a; },
            dec: function() { --a; },
            get: function() { return a; },
            reset: function() { a = 0; }
        }
    }
  3. विदेशी प्रवाह नियंत्रण को लागू करना, जैसे कि jQuery का इवेंट हैंडलिंग और AJAX एपीआई।


3
( int?) अंतिम बार मैंने जाँच की, जावास्क्रिप्ट एक टंकित भाषा थी। शायद आप जावा के बारे में सोच रहे थे?
हैलो71

1
@ Hello71: मैं जावास्क्रिप्ट के बारे में सोच रहा था, लेकिन पुरानी आदतें कठिन मर जाती हैं। अच्छी पकड़।
मार्सेलो कैंटोस

2
@MarceloCantos ऐसा लगता है कि आप काउंटर के कार्यान्वयन में एक अल्पविराम भूल गए हैं। मैंने इसे ठीक करने के लिए आपकी पोस्ट को संपादित किया। आशा है कि यह ठीक है :)
नटन स्ट्रेपल 16

2
@Streppel: अच्छी पकड़! मेरे कोड को बेहतर बनाने के लिए मैं आपसे अधिक खुश हूं। :-)
मार्सेलो कैंटोस

# 1 को समझने की कोशिश कर रहा है ... आप निकटता को कैसे कहेंगे?
डेव २०81१

26

मुझे पता है कि मैं इस सवाल का जवाब देने में सुपर लेट हूं लेकिन यह 2018 में किसी को भी उत्तर की खोज में मदद कर सकता है।

जावास्क्रिप्ट क्लोजर का उपयोग आपके एप्लिकेशन में थ्रॉटल और डेब्यू कार्यक्षमता को लागू करने के लिए किया जा सकता है ।

थ्रॉटलिंग :

थ्रॉटलिंग एक सीमा को लागू करता है क्योंकि एक फ़ंक्शन को समय के साथ अधिकतम संख्या में कहा जा सकता है। जैसा कि "प्रत्येक 100 मिलीसेकंड पर एक बार इस फ़ंक्शन को निष्पादित करें।"

कोड:

const throttle = (func, limit) => {
  let isThrottling
  return function() {
    const args = arguments
    const context = this
    if (!isThrottling) {
      func.apply(context, args)
      isThrottling = true
      setTimeout(() => isThrottling = false, limit)
    }
  }
}

डिबगिंग :

किसी फ़ंक्शन पर डिबॉन्डिंग ने एक सीमा पर फिर से कॉल नहीं किया जब तक कि निश्चित समय बीतने के बिना इसे बुलाया नहीं जाता। जैसा कि "इस फ़ंक्शन को केवल तभी निष्पादित करें यदि 100 मिलीसेकंड इसे पारित किए बिना कहा जाता है।"

कोड:

const debounce = (func, delay) => {
  let debouncing
  return function() {
    const context = this
    const args = arguments
    clearTimeout(debouncing)
    debouncing = setTimeout(() => func.apply(context, args), delay)
  }
}

जैसा कि आप देख सकते हैं कि क्लोजर ने दो सुंदर सुविधाओं को लागू करने में मदद की है जो हर वेब ऐप को सुचारू यूआई अनुभव कार्यक्षमता प्रदान करनी चाहिए।

मुझे उम्मीद है कि यह किसी की मदद करेगा।


18

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

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

for (var i = 0; i < someVar.length; i++)
    window.setTimeout(function () { 
        alert("Value of i was "+i+" when this timer was set" )
    }, 10000);

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

for (var i = 0; i < someVar.length; i++)
    (function (i) {
        window.setTimeout(function () { 
            alert("Value of i was "+i+" when this timer was set" )
        }, 10000);
    })(i); 

दिलचस्प -1, मुझे लगता है कि यह "जावास्क्रिप्ट में एक बंद करने के लिए एक व्यावहारिक उपयोग" नहीं है?
एंडी ई

1
मुझे इसे पढ़ने में कुछ फायदा हुआ इसलिए मैंने डाउनवोट से पहले एक +1 से सम्मानित किया।
एलेक्स

1
@alex: धन्यवाद, मैंने upvote को नोटिस किया। मैंने लगभग SO पर अनाम डाउनवोट्स का उपयोग किया है। यह केवल मुझे गुस्सा दिलाता है क्योंकि मैं वास्तव में जानना चाहता हूं कि क्या मैंने कुछ गलत या गलत कहा है, और वे आपको यह सोचने के लिए प्रेरित करते हैं कि आपको बस कुछ अन्य उत्तरदाता द्वारा अस्वीकार कर दिया गया है जो अपने स्वयं के उत्तर के लिए बेहतर दृश्यता चाहते हैं। सौभाग्य से, मैं तामसिक प्रकार नहीं हूं ;-)
एंडी ई

1
मुझे लगता है कि यह जावा ब्लॉक के टूटे हुए दायरे के लिए अधिक काम है। आपको बस var j = i जोड़ना चाहिए; पहले सेटटाइमआउट से पहले और उस j का उपयोग करने के लिए अलर्ट प्राप्त करें। आस-पास एक अन्य कार्य 'जैसे' का उपयोग करना है: जैसे (var i = 0; मैं <someVar.length; i ++) {with ({i: i}) {window.setTimeout (function () {alert ("मान" मैं "+ i +" था जब यह टाइमर सेट किया गया था ")}, 100);}}}
davidbuttar

1
@AndyE फनी सही शब्द नहीं हो सकता है। मैंने अभी देखा कि अक्सर लोग इस पृष्ठ पर कई उत्तरों की तरह, क्लोजर को समझाने के लिए सेल्फ-इनवॉइसिंग फंक्शन्स का उपयोग करते हैं। लेकिन सेटटाइम में कॉलबैक फ़ंक्शन भी एक बंद है; कॉलबैक से कुछ अन्य स्थानीय चर तक पहुँचने के बाद से इसे "एक व्यावहारिक उपयोग" माना जा सकता है। जब मैं क्लोज़र के बारे में सीख रहा था, तब यह महसूस करना मेरे लिए उपयोगी था - कि क्लोज़र हर जगह हैं, न कि केवल आर्केड जावास्क्रिप्ट पैटर्न में।
एंटोनी

14

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

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

var dateUtil = {
  weekdayShort: (function() {
    var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
    return function(x) {
      if ((x != parseInt(x)) || (x < 1) || (x > 7)) {
        throw new Error("invalid weekday number");
      }
      return days[x - 1];
    };
  }())
};

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


2
यह गूंगा लग सकता है, लेकिन क्या वे केवल जावास्क्रिप्ट फ़ाइल को ही नहीं खोल सकते हैं और आपके कार्यान्वयन को देख सकते हैं?
इसका वर्चस्व

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

6

इसके माध्यम से देखते हुए, मैं यह नहीं देखता कि यह "व्यावहारिक" कैसे है क्योंकि मैं पूरे return function ()...कोड को हटा देता हूं फिर भी ठीक काम करता है। क्लोजर
नेस्सेरी

@James_Parsons फिर आप उन्हें घटना संचालकों को सौंप नहीं सकते हैं जैसे कि उन्होंने उदाहरण में किया है।
एलेक्स

5

क्लोजर के लिए एक और सामान्य उपयोग thisएक विधि में एक विशिष्ट वस्तु से बांधना है, जिससे इसे कहीं और बुलाया जा सकता है (जैसे कि घटना हैंडलर के रूप में)।

function bind(obj, method) {
    if (typeof method == 'string') {
        method = obj[method];
    }
    return function () {
        method.apply(obj, arguments);
    }
}
...
document.body.addEventListener('mousemove', bind(watcher, 'follow'), true);

जब भी मूसमव इवेंट में आग लग जाती है, watcher.follow(evt)कहा जाता है।

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

foo_a = function (...) {A a B}
foo_b = function (...) {A b B}
foo_c = function (...) {A c B}

हो जाता है

fooer = function (x) {
    return function (...) {A x B}
}

जहाँ A और B सिंटैक्टिकल इकाइयाँ नहीं हैं, लेकिन स्रोत कोड स्ट्रिंग्स (स्ट्रिंग लिटरल्स नहीं हैं)।

एक ठोस उदाहरण के लिए " एक फ़ंक्शन के साथ मेरी जावास्क्रिप्ट को व्यवस्थित करें " देखें ।


5

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

बिना बंद किए ( https://jsfiddle.net/lukeschlangen/pw61qrow/3/ ):

function greeting(firstName, lastName) {
  var message = "Hello " + firstName + " " + lastName + "!";
  console.log(message);
}

greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");

एक बंद ( https://jsfiddle.net/lukeschlangen/Lb5cfve9/3/ ) के साथ:

function greeting(firstName, lastName) {
  var message = "Hello " + firstName + " " + lastName + "!";

  return function() {
    console.log(message);
  }
}

var greetingBilly = greeting("Billy", "Bob");
var greetingLuke = greeting("Luke", "Schlangen");

greetingBilly();
greetingBilly();
greetingBilly();
greetingLuke();
greetingLuke();
greetingLuke();

1
मुझे यकीन नहीं है, लेकिन फिर भी बिना क्लोजर यू को वर्ट्रीबिली = ग्रीटिंग ("बिली", "बॉब") कहा जा सकता है; और कॉल ग्रैटबिली (); यह अभी भी ऐसा ही होगा ?? यद्यपि आप क्लोज़र बनाते हैं या एक अलग मुद्दा नहीं है, लेकिन हर बार नाम पास करना यहां कोई समस्या नहीं है।
user2906608

4

यदि आप किसी कक्षा को ऑब्जेक्ट-ओरिएंटेड अर्थों में तात्कालिक बनाने की अवधारणा के साथ सहज हैं (यानी उस वर्ग का ऑब्जेक्ट बनाने के लिए) तो आप क्लोजर को समझने के करीब हैं।

इसे इस तरह से सोचें: जब आप दो व्यक्ति वस्तुओं को पलटाते हैं, तो आप जानते हैं कि वर्ग सदस्य चर "नाम" उदाहरणों के बीच साझा नहीं किया गया है; प्रत्येक वस्तु की अपनी 'प्रति' होती है। इसी तरह, जब आप एक क्लोजर बनाते हैं, तो निशुल्क चर ('उदाहरण में आपके उदाहरण में' callCount ') फ़ंक्शन के' उदाहरण 'के लिए बाध्य है।

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

इसलिए, मान लीजिए कि 'कॉलकाउंट' एक निश्चित मूल्य तक पहुँच जाता है जिसे आप उपयोगकर्ता के सत्र को समाप्त करना चाहते हैं; आप इसके लिए अलग-अलग मान चाहते हैं कि यह अनुरोध स्थानीय नेटवर्क या बड़े बुरे इंटरनेट से आता है या नहीं (हां, यह एक बहुत अच्छा उदाहरण है)। इसे प्राप्त करने के लिए, आप विभिन्न प्रारंभिक मानों को वॉर्नयूज़र (यानी -3, या 0?) में कह सकते हैं।

साहित्य के साथ समस्या का एक हिस्सा उनका वर्णन करने के लिए उपयोग किया जाने वाला नामकरण है ("लेक्सिकल स्कोप", "मुक्त चर")। यह आपको मूर्ख मत बनने दो, क्लोजर दिखने में जितना आसान होगा ... प्राइमा फेशी ;-)


3

यहां मेरे पास क्लोजर कॉन्सेप्ट का एक सरल उदाहरण है जिसे हम अपनी ई-कॉमर्स साइट या कई अन्य लोगों के लिए भी उपयोग कर सकते हैं। मैं अपने jsfiddle लिंक को उदाहरण के साथ जोड़ रहा हूं। इसमें 3 आइटम और एक कार्ट काउंटर की एक छोटी उत्पाद सूची शामिल है।

Jsfiddle

//Counter clouser implemented function;
var CartCouter = function(){
	var counter = 0;
  function changeCounter(val){
  	counter += val
  }
  return {
  	increment: function(){
    	changeCounter(1);
    },
    decrement: function(){
    changeCounter(-1);
    },
    value: function(){
    return counter;
    }
  }
}

var cartCount = CartCouter();
function updateCart(){
	document.getElementById('cartcount').innerHTML = cartCount.value();
  }

var productlist = document.getElementsByClassName('item');
for(var i = 0; i< productlist.length; i++){
	productlist[i].addEventListener('click',function(){
  	if(this.className.indexOf('selected')<0){
    		this.className += " selected";
        cartCount.increment();
        updateCart();
    } else{
    	this.className = this.className.replace("selected", "");
      cartCount.decrement();
      updateCart();
    }
  })
}
.productslist{
  padding:10px;
}
ul li{
  display: inline-block;
  padding: 5px;
  border: 1px solid #ddd;
  text-align: center;
  width: 25%;
  cursor: pointer;
}
.selected{
  background-color: #7CFEF0;
  color: #333;
}
.cartdiv{
  position: relative;
  float:right;
  padding: 5px;
  box-sizing: border-box;
  border: 1px solid #f1f1f1;
}
<div>
<h3>
Practical Use of JavaScript Closure consept/private variable.
</h3>
<div class="cartdiv">
    <span id="cartcount">0</span>
</div>
<div class="productslist">
    <ul >
    <li class="item">Product 1</li>
     <li class="item">Product 2</li>
     <li class="item">Product 3</li>
    </ul>

</div>
</div>


2

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

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

उदाहरण :

<script>
var createPet = function(name) {
  var sex;

  return {
    setName: function(newName) {
      name = newName;
    },

    getName: function() {
      return name;
    },

    getSex: function() {
      return sex;
    },

    setSex: function(newSex) {
      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
console.log(pet.getName());                  // Vivie

console.log(pet.setName("Oliver"));   
console.log(pet.setSex("male"));
console.log(pet.getSex());                   // male
console.log(pet.getName());                  // Oliver
</script>

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


2

मुझे मोजिला का फंक्शन फैक्ट्री उदाहरण पसंद है

function makeAdder(x) {

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

var addFive = makeAdder(5);

console.assert(addFive(2) === 7); 
console.assert(addFive(-5) === 0);

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

2

जावास्क्रिप्ट मॉड्यूल पैटर्न क्लोजर का उपयोग करता है। इसका अच्छा पैटर्न आपको कुछ समान "सार्वजनिक" और "निजी" संस्करण की अनुमति देता है।

var myNamespace = (function () {

  var myPrivateVar, myPrivateMethod;

  // A private counter variable
  myPrivateVar = 0;

  // A private function which logs any arguments
  myPrivateMethod = function( foo ) {
      console.log( foo );
  };

  return {

    // A public variable
    myPublicVar: "foo",

    // A public function utilizing privates
    myPublicFunction: function( bar ) {

      // Increment our private counter
      myPrivateVar++;

      // Call our private method using bar
      myPrivateMethod( bar );

    }
  };

})();

1

इवेंट-हैंडलिंग कोड को सरल बनाने के लिए क्लोजर का उपयोग कैसे किया जा सकता है, इसके बारे में मैंने कुछ समय पहले एक लेख लिखा था। यह ASP.NET इवेंट हैंडलिंग की क्लाइंट-साइड jQuery से तुलना करता है।

http://www.hackification.com/2009/02/20/closures-simplify-event-handling-code/


1

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

कृपया विशेषज्ञों, मुझे बताएं कि क्या मैंने यहां कोई बुरा व्यवहार किया है! मैं अब भी यह सामान खुद ही सीख रहा हूं।

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Closures on button presses</title>
<script type="text/javascript">

window.addEventListener("load" , function () {
    /*
    grab the function from the first closure,
    and assign to a temporary variable 
    this will set the totalButtonCount variable
    that is used to count the total of all button clicks

    */
    var buttonHandler = buttonsCount(); 

    /*
    using the result from the first closure (a function is returned) 
    assign and run the sub closure that carries the 
    individual variable for button count and assign to the click handlers 
    */
    document.getElementById("button1").addEventListener("click" , buttonHandler() );
    document.getElementById("button2").addEventListener("click" , buttonHandler() );
    document.getElementById("button3").addEventListener("click" , buttonHandler() );

    // Now that buttonHandler has served its purpose it can be deleted if needs be
    buttonHandler = null;
});



function buttonsCount() {
    /* 
        First closure level 
        - totalButtonCount acts as a sort of global counter to count any button presses
    */
    var totalButtonCount = 0;

    return  function () {
        //second closure level
        var myButtonCount = 0;

        return function (event) {
            //actual function that is called on the button click
            event.preventDefault();
            /*  
               increment the button counts.
               myButtonCount only exists in the scope that is 
               applied to each event handler, therefore acts 
               to count each button individually whereas because 
               of the first closure totalButtonCount exists at 
               the scope just outside, so maintains a sort 
               of static or global variable state 
            */

            totalButtonCount++;
            myButtonCount++;

            /* 
                do something with the values ... fairly pointless 
                but it shows that each button contributes to both 
                it's own variable and the outer variable in the 
                first closure 
            */
            console.log("Total button clicks: "+totalButtonCount);
            console.log("This button count: "+myButtonCount);
        }
    }
}

</script>
</head>

<body>
    <a href="#" id="button1">Button 1</a>
    <a href="#" id="button2">Button 2</a>
    <a href="#" id="button3">Button 3</a>
</body>
</html>

0

संदर्भ: क्लोजर का व्यावहारिक उपयोग

व्यवहार में क्लोजर सुरुचिपूर्ण डिजाइन बना सकते हैं, विभिन्न गणनाओं के अनुकूलन, आस्थगित कॉल, कॉलबैक, इनकैप्सुलेटेड स्कोप आदि का निर्माण कर सकते हैं।

एरे की तरह विधि का एक उदाहरण जो एक तर्क को सॉर्ट-कंडीशन फ़ंक्शन के रूप में स्वीकार करता है:

[1, 2, 3].sort(function (a, b) {
    ... // sort conditions
});

फ़ंक्शंस के मानचित्र विधि के रूप में फ़ंक्शंस को मैप करना जो कार्यात्मक तर्क की स्थिति से एक नए सरणी को मैप करता है:

[1, 2, 3].map(function (element) {
   return element * 2;
}); // [2, 4, 6]

अक्सर खोज के लिए लगभग असीमित स्थितियों को परिभाषित करने वाले कार्यात्मक तर्कों का उपयोग करके खोज कार्यों को लागू करना सुविधाजनक होता है:

 someCollection.find(function (element) {
        return element.someProperty == 'searchCondition';
    });

इसके अलावा, हम कार्यात्मक रूप से लागू करने पर ध्यान दे सकते हैं, उदाहरण के लिए, एक पूर्व विधि जो तत्वों के एक सरणी पर एक फ़ंक्शन लागू करती है:

[1, 2, 3].forEach(function (element) {
    if (element % 2 != 0) {
        alert(element);
    }
}); // 1, 3

एक फ़ंक्शन को तर्कों पर लागू किया जाता है (तर्कों की एक सूची में - लागू करने के लिए, और तर्कों को तैनात करने के लिए - कॉल में):

(function () {
  alert([].join.call(arguments, ';')); // 1;2;3
}).apply(this, [1, 2, 3]);

आस्थगित कॉल:

var a = 10;
    setTimeout(function () {
      alert(a); // 10, after one second
    }, 1000);

कॉलबैक कार्य:

var x = 10;
// only for example
xmlHttpRequestObject.onreadystatechange = function () {
  // callback, which will be called deferral ,
  // when data will be ready;
  // variable "x" here is available,
  // regardless that context in which,
  // it was created already finished
  alert(x); // 10
};

सहायक वस्तुओं को छिपाने के उद्देश्य के लिए एक समझाया गुंजाइश का निर्माण:

var foo = {};
(function (object) {
  var x = 10;
  object.getX = function _getX() {
    return x;
  };
})(foo);
alert(foo.getX());// get closured "x" – 10

0

अधिकांश कोड जो हम फ्रंट-एंड जावास्क्रिप्ट में लिखते हैं, घटना-आधारित है - हम कुछ व्यवहार को परिभाषित करते हैं, फिर इसे एक ऐसी घटना से जोड़ते हैं जो उपयोगकर्ता द्वारा ट्रिगर किया जाता है (जैसे कि एक क्लिक या एक कुंजीपट)। हमारा कोड आम तौर पर कॉलबैक के रूप में संलग्न होता है: एक एकल फ़ंक्शन जिसे घटना के जवाब में निष्पादित किया जाता है। size12, size14, और size16 अब फ़ंक्शंस हैं जो क्रमशः 12, 14 और 16 पिक्सेल के बॉडी टेक्स्ट का आकार बदल देंगे। हम उन्हें बटन (इस मामले में लिंक) में संलग्न कर सकते हैं:

function makeSizer(size) {
    return function() {
    document.body.style.fontSize = size + 'px';
    };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

बेला


हालांकि यह कोड प्रश्न का उत्तर दे सकता है, लेकिन यह समस्या का हल कैसे और / या इसके बारे में अतिरिक्त संदर्भ प्रदान करता है, इससे उत्तर के दीर्घकालिक मूल्य में सुधार होगा।
डोनाल्ड डक

1
यह उदाहरण, यह मुझे लगता है, एक मानक समारोह के माध्यम से बंद किए बिना लागू किया जा सकता है। मैं कुछ का एक उदाहरण खोजने की कोशिश कर रहा हूं जो COULDN'S को बंद किए बिना लागू किया जाएगा
Zach Smith

0

क्लोजर बनाने का एक उपयोगी तरीका है , मांग में वृद्धि का क्रम:

    var foobar = function(i){var count = count || i; return function(){return ++count;}}

    baz = foobar(1);
    console.log("first call: " + baz()); //2
    console.log("second call: " + baz()); //3

मतभेद इस प्रकार हैं:

बेनामी फ़ंक्शंस परिभाषित कार्य

एक विधि के रूप में इस्तेमाल नहीं किया जा सकता है एक वस्तु की एक विधि के रूप में इस्तेमाल किया जा सकता है

केवल उस दायरे में मौजूद है जिसमें इसे परिभाषित किया गया है वस्तु के भीतर मौजूद है जो इसे परिभाषित किया गया है

केवल उस दायरे में बुलाया जा सकता है जिसमें इसे परिभाषित किया गया है जिसे कोड के किसी भी बिंदु पर बुलाया जा सकता है

एक नया मान पुन: असाइन किया जा सकता है या हटाया नहीं जा सकता या हटाया नहीं जा सकता

संदर्भ


0

दिए गए नमूने में संलग्न चर 'काउंटर' का मूल्य संरक्षित है और केवल दिए गए कार्यों (वेतन वृद्धि, वृद्धि) का उपयोग करके बदला जा सकता है। क्योंकि यह एक बंद में है,

var MyCounter= function (){
    var counter=0;
    return {
    	increment:function () {return counter += 1;},
        decrement:function () {return counter -= 1;},
        get:function () {return counter;}
    };
};

var x = MyCounter();
//or
var y = MyCounter();

alert(x.get());//0
alert(x.increment());//1
alert(x.increment());//2

alert(y.increment());//1
alert(x.get());// x is still 2


0

जावास्क्रिप्ट में एक बंद करने के लिए व्यावहारिक उपयोग की व्याख्या ---

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

इस तरह के समारोह का एक सरल उदाहरण यह है:

function buildName(name) { 
    const greeting = "Hello, " + name; 
    return greeting;
}

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

लेकिन कैसे जब हम उस दायरे के लिए एक कड़ी है?

आइए अगले समारोह को देखें:

function buildName(name) { 
    const greeting = "Hello, " + name + " Welcome "; 
    const sayName = function() {
        console.log(greeting); 
    };
    return sayName; 
}

const sayMyName = buildName("Mandeep");
sayMyName();  // Hello, Mandeep Welcome

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

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


0

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

function createUserWarningData(user) {
  const data = {
    name: user,
    numberOfWarnings: 0,
  };

  function addWarning() {
    data.numberOfWarnings = data.numberOfWarnings + 1;
  }

  function getUserData() {
    console.log(data);
    return data;
  }

  return {
    getUserData: getUserData,
    addWarning: addWarning,
  };
}

const user1 = createUserWarningData("Thomas");
const user2 = createUserWarningData("Alex");

//USER 1
user1.getUserData(); // returning data user object
user1.addWarning(); // add one warning to specific user
user1.getUserData(); // returning data user object

//USER2
user2.getUserData(); // returning data user object
user2.addWarning(); // add one warning to specific user
user2.addWarning(); // add one warning to specific user
user2.getUserData(); // returning data user object

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.