क्लोज़र JavaScript में एक प्रोग्रामिंग पैटर्न है, जिसकी मदद से बाहरी लेक्सिकल स्कोप के वेरिएबल को कोड के किसी नेस्टेड ब्लॉक के अंदर इस्तेमाल किया जा सकता है। JavaScript क्लोज़र को सहज ही समर्थन देता है, और अक्सर इन्हें यह जाने बिना ही इस्तेमाल किया जाता है कि ये असल में क्या हैं।
// Top-level declarations are global-scope
const dozen = 12;
{
// Braces create a new block-scope
// Referencing the outer variable is a closure.
const twoDozen = dozen * 2;
}
// Because of the block-scope declaration, twoDozen is not available here.
twoDozen;
// => Uncaught ReferenceError: twoDozen is not defined
घुंघराले ब्रैकेट {} के अलावा, फंक्शन (और क्लास) भी नए स्कोप बनाते हैं, और वैल्यू को अपने अंदर समेट सकते हैं:
const dozen = 12;
// Functions create a new function-scope and block-scope.
// Referencing the outer variable here is a closure.
function nDozen(n) {
// This is declared inside the function scope, and uses the top-level scope.
// This works, and encloses the value 12.
const twoDozen = dozen * 2;
// This only uses the locally declared variable and the passed argument to the parameter `n`
return (twoDozen / 2) * n;
}
// Because of the function-scope declaration, twoDozen is not available here.
twoDozen;
// => Uncaught ReferenceError: twoDozen is not defined
जैसा कि twoDozen के उदाहरणों से दिखता है, वैल्यू को किसी नेस्टेड स्कोप (फंक्शन, ब्लॉक वगैरह) के अंदर समेटा जा सकता है, लेकिन उस संदर्भ से बाहर नहीं निकाला जा सकता।
आधुनिक JavaScript में ज़्यादातर मामलों में यही चाहा जाता है कि कोई वैल्यू बाहरी स्कोप में रिस न जाए।
let या var जैसी बदली जा सकने वाली वेरिएबल घोषणा से कुछ स्थिति सहेजकर रखी जा सकती है:
let counter = 0;
// This function closure increments the counter's state in the outer lexical context.
// This way the counter can be shared between many calling contexts.
export function increment() {
counter += 1;
return counter;
}
increment();
// => 1
counter;
// => 1
अब दोनों बातें मिलाइए: वैल्यू को अंदर समेटकर स्थिति सहेजना, और अंदर समेटी गई वैल्यू का बाहर न रिसना। इन दोनों को मिलाकर प्राइवेट वैल्यू बनाई जा सकती हैं।
सबसे आम तरीका यह है कि ऐसा फंक्शन बनाया जाए जो एक और फंक्शन लौटाए, और वह लौटाया गया फंक्शन कुछ स्थिति को अपने अंदर समेट ले।
export function makeCounter() {
let counter = 0;
// This returns a new function that encloses the local variable counter
return function increment() {
counter += 1;
return counter;
};
}
// Counter did not leak
counter;
// => Uncaught ReferenceError: counter is not defined
// This creates a new counter.
// This assigns the increment function to the variable myFirstCounter.
const myFirstCounter = makeCounter();
typeof myFirstCounter;
// => function
myFirstCounter.name;
// => increment
myFirstCounter();
// => 1
myFirstCounter();
// => 2
// This creates new counter (with new, separate local state / enclosed counter variable)
const mySecondCounter = makeCounter();
mySecondCounter();
// => 1
// It does not affect the first counter.
myFirstCounter();
// => 3
कई प्रोग्रामर को क्लोज़र कठिन कॉन्सेप्ट लगता है, और एक फंक्शन से दूसरा फंक्शन लौटाना सभी प्रोग्रामिंग भाषाओं में न तो आम है, और कुछ में तो मुमकिन भी नहीं है। अगर आप और पढ़ना चाहें, तो MDN पर क्लोज़र की गाइड काफी विस्तृत है।
आपकी डिज़ाइन कंपनी अब तक वेब पेज बनाने के लिए मुख्य रूप से CSS ट्रांसफॉर्मेशन का उपयोग करती आ रही है। कुछ चर्चा के बाद तय हुआ कि अब कुछ गणनाएँ गतिशील रूप से करने के लिए JavaScript का उपयोग शुरू किया जाए। आपकी टीम के कुछ साथियों को JavaScript का अनुभव कम है। इसलिए आप {x, y} निर्देशांक जोड़ों के लिए दोबारा उपयोग हो सकने वाला ट्रांसफॉर्मेशन बनाने के लिए फंक्शन क्लोज़र का उपयोग करने का फैसला करते हैं।
translate2d फंक्शन बनाइए, जो एक ऐसा फंक्शन लौटाता है जो क्लोज़र का उपयोग करके किसी निर्देशांक जोड़े का दोबारा किया जा सकने वाला दो-आयामी स्थानांतरण करता है।
ज्यामिति में, स्थानांतरण का अर्थ है किसी बिंदु, सदिश या आकृति को एक ही दिशा में समान दूरी तक खिसकाना। इसे हर बिंदु में एक स्थिरांक जोड़ने के रूप में समझा जा सकता है।
const moveCoordinatesRight2Px = translate2d(2, 0);
const result = moveCoordinatesRight2Px(4, 8);
// result => [6, 8]
scale2d फंक्शन बनाइए, जो एक ऐसा फंक्शन लौटाता है जो क्लोज़र का उपयोग करके किसी निर्देशांक जोड़े की दोबारा की जा सकने वाली दो-आयामी स्केलिंग करता है।
ज्यामिति में, समान स्केलिंग का अर्थ है सदिशों या आकृतियों को एक ही दिशा में बड़ा या छोटा करना। इसे हर बिंदु को एक स्थिरांक (स्केलिंग गुणक) से गुणा करने के रूप में समझा जा सकता है।
इस अभ्यास में मान लीजिए कि स्केलिंग की सभी वैल्यू धनात्मक ही होंगी।
const doubleScale = scale2d(2, 2);
const result = doubleScale(6, -3);
// result => [12, -6]
दो ट्रांसफॉर्मेशन फंक्शन संयोजित करके एक दोबारा किया जा सकने वाला ट्रांसफॉर्मेशन बनाइए। इसे अक्सर फंक्शन संयोजन कहा जाता है, जिसमें पहले फंक्शन 'f(x)' का परिणाम दूसरे फंक्शन 'g(x)' को इनपुट के रूप में दिया जाता है।
const moveCoordinatesRight2Px = translate2d(2, 0);
const doubleCoordinates = scale2d(2, 2);
const composedTransformations = composeTransform(
moveCoordinatesRight2Px,
doubleCoordinates,
);
const result = composedTransformations(0, 1);
// result => [4, 2]
memoizeTransform फंक्शन बनाइए। यह उस फंक्शन को लेता है जिसे मेमोइज़ करना है, और फिर एक नया फंक्शन लौटाता है जो उस फंक्शन को दिए गए इनपुट याद रखता है। इससे अंतिम रिटर्न वैल्यू "याद" रह जाती है, और उसी आर्गुमेंट के साथ दोबारा कॉल करने पर वह केवल एक बार ही गणना की जाती है।
मेमोइज़िंग का उपयोग कभी-कभी डायनैमिक प्रोग्रामिंग में किया जाता है। इससे भारी ऑपरेशन केवल एक बार ही करने पड़ते हैं, क्योंकि उनके परिणाम याद रखे जाते हैं। ध्यान दें कि इस अभ्यास में केवल अंतिम परिणाम ही याद रखा जाता है, जबकि डायनैमिक प्रोग्रामिंग के कुछ हल सभी परिणाम मेमोइज़ करते हैं।
const tripleScale = scale2d(3, 3);
const memoizedScale = memoizeTransform(tripleScale);
memoizedScale(4, 3); // => [12, 9], this is computed since it hasn't been computed before for the arguments
memoizedScale(4, 3); // => [12, 9], this is remembered, since it was computed already
Exercism पर साइन अप कीजिए और JavaScript को 37 कॉन्सेप्ट159 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।