जावास्क्रिप्ट में न-अनाम कार्यों की सुंदरता

छवि


कुछ चुनावों के अनुसार, जावास्क्रिप्ट में अनाम तीर फ़ंक्शन ES-2015 की सबसे लोकप्रिय विशेषता है, जिसे इंटरनेट पर व्यापक ट्यूटोरियल द्वारा भी रेखांकित किया गया है। वे निर्विवाद रूप से बहुत उपयोगी हैं, लेकिन इस छोटे से लेख में हम नामित कार्यों के साथ कम से कम अद्भुत अभिव्यक्तियों से वंचितों का उपयोग करने के उदाहरणों पर ध्यान देंगे - NFE।


लघु सहायता


नामित फ़ंक्शन अभिव्यक्ति - जावास्क्रिप्ट में कार्यात्मक अभिव्यक्तियों का एक विस्तार जो आपको अभिव्यक्ति के भाग के रूप में बनाए गए फ़ंक्शन का नाम देने की अनुमति देता है ( फ़ंक्शन एक्सप्रेशन):


let fe = function named(...) { /* function body */ }; 

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


इसका उपयोग कैसे करें


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


 const count = f => function df() { df.calls = (df.calls || 0) + 1; return f(...arguments); }; 

यहां हमें दिए गए df फ़ंक्शन तक पहुंच प्राप्त हुई, ताकि जब इसे कॉल किया जाए, तो हम कॉल प्रॉपर्टी में काउंटर को सेव करें, जो कि आवश्यक होने पर पढ़ने के लिए उपलब्ध होगा:


 const csum = count((x, y) => x + y); csum(5, 10); // 15 csum(50, 1); // 51 csum.calls; // 2 

या फ़ंक्शन कॉल के सभी परिणाम सहेजें:


 const accum = f => function df() { let res = f(...arguments); (df.results = (df.results || [])).push(res); return res; }; 

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


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


 const rf = function getfn(n) { return n > 2 ? getfn(n - 2) + getfn(n - 1) : 1; }; rf(1); // 1 rf(10); // 55 

यहां "पूंछ" पर ध्यान देने योग्य नहीं है। लेकिन FunctionDeclaration के माध्यम से भी ऐसा करने की क्षमता पर - हाँ। लेकिन अभिव्यक्ति फ़ंक्शन का एक फायदा है: यदि आप फ़ंक्शन को आरएफ से दूसरे चर में स्थानांतरित करना चाहते हैं, तो आपको पुनरावर्ती कॉल को संपादित करने की आवश्यकता नहीं है।


टाइमर कार्यान्वयन का एक साफ उदाहरण:


 const ping = (callback, t) => setTimeout(function pf() { callback(); setTimeout(pf, t); }, t); 

यहाँ हम NFE को एक अनावश्यक चर घोषित करने के बजाय एक तर्क के रूप में शाब्दिक रूप में उपयोग करते हैं। क्यों सेट नहीं किया गया? कॉलबैक के बजाय, टाइमर के अगले टिक से पहले वादे के समाधान के लिए इंतजार करना पड़ सकता है।


एक दिलचस्प उदाहरण NFE और IIFE ( तत्काल-इनवॉल्ड फंक्शन एक्सप्रेशन ) का संयोजन होगा, जब जगह में केवल पुनरावर्ती फ़ंक्शन के परिणाम की आवश्यकता होती है। बस एक बार:


 let data = { f10: function fact(n) { return n > 1 ? n * fact(n - 1) : 1; }(10) }; data.f10; // 3628800 

क्या ऐसा है? ठीक है, यहाँ वास्तविक समस्या है: कुछ सख्ती से बढ़ रही फ़ंक्शन च है जो प्राकृतिक संख्याओं के सेट में कार्य करता है। चरम बिंदु x का पता लगाएं जिस पर फ़ंक्शन का मान दिए गए y से अधिक नहीं है। ऐसे फ़ंक्शन का एक उदाहरण f(x) = 3 * x + 5 या f(x) = 2^x + 11


 const find = (f, y) => function bs(a, b) { if (a + 1 === b) return a; let m = Math.ceil((a + b) / 2); return f(m) <= y ? bs(m, b) : bs(a, m); }(-1, y + 1); find(x => 3 * x + 5, 200); // 65 find(x => Math.pow(2, x) + 11, 1000); // 9 

हम गणितीय विवरण में नहीं जाएंगे। कार्यान्वयन पर विचार करें:


  1. आवश्यक खोज फ़ंक्शन में हमारे दो पैरामीटर f, y हैं और IIFE का परिणाम देता है।
  2. एक फंक्शन नामक तुरंत एक समाधान के लिए एक द्विआधारी खोज को लागू करता है, पहली कॉल को प्रारंभिक सीमा मिलती है।
  3. खोज को पुनरावृत्ति के माध्यम से कार्यान्वित किया जाता है, जो बाद की कॉल के लिए NFE नाम का उपयोग करता है। हम एक खोज फ़ंक्शन घोषित नहीं करते हैं और एक नया चर नहीं बनाते हैं।

बेशक, एक समान समस्या को एक पूर्व शर्त के साथ एक सरल चक्र के माध्यम से हल किया जा सकता है, लेकिन कंसोल कोडिंग के लिए यह बहुत जरूरी है।


अंत में, स्टैक ट्रेस के बारे में कुछ शब्द। हमारे पास कुछ NFE फ़ंक्शन हैं, जिनके शरीर में एक अपवाद फेंक दिया गया था:


 const fe = function named() { throw new Error('Something went wrong'); }; 

चूंकि हमारे पास अभिव्यक्ति में एक नामित फ़ंक्शन है, हम इसे स्टैक ट्रेस में देखेंगे:


 Uncaught Error: Something went wrong at named (<anonymous>:2:11) 

हालांकि, ईएस -2015 में शुरू, कई अनाम फ़ंक्शन फ़ंक्शन वास्तव में एक नाम के साथ एक फ़ंक्शन बनाते हैं, इसे संदर्भ से बाहर निकालते हैं:


 const unnamed = function() { throw new Error('Something went wrong'); }; 

अभिव्यक्ति के दाईं ओर फ़ंक्शन बाईं ओर चर के साथ जुड़ा हुआ है:


 Uncaught Error: Something went wrong at unnamed (<anonymous>:2:7) 

लेकिन यह हमेशा संभव नहीं होता है। एक क्लासिक उदाहरण एक विकल्प के रूप में IIFE के माध्यम से एक बाहरी पुस्तकालय लिपि का आरंभ है:


 /** * @license * @description */ ;(function() { // some awesome code }.call(this)); 

या किसी अन्य फ़ंक्शन को वापस करने वाले फ़ंक्शन का अक्सर उदाहरण:


 const bind = (f, ctx) => function() { return f.apply(ctx, arguments); }; 

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


संक्षिप्त निष्कर्ष


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

Source: https://habr.com/ru/post/hi427461/


All Articles