किसी तरह अपने आप के लिए, मैंने कक्षाओं और पैटर्न के साथ उपद्रव से दूर जाने का फैसला किया, और सबसे आम जेएस कार्यों के साथ सौदा किया। मुझे लगा कि यह काफी उबाऊ होगा, लेकिन मैंने एक गलती की - यह बहुत दिलचस्प निकला।
इस लेख में मैं कार्यों की घोषणा की विशेषताओं के बारे में बात करूंगा, और कुछ उपयोगी पैटर्न (हे, हां, वे यहां भी हैं)
1. समारोह की घोषणा
यदि आप सभी प्रकार की विकृतियों पर ध्यान नहीं देते हैं, तो आप केवल दो तरीकों से एक समारोह की घोषणा कर सकते हैं:
// function a() { console.log(1); } // , b = function() { console.log(2); }
उनके बीच अंतर छोटा लगता है, लेकिन यह केवल लगता है।
इस कोड को निष्पादित करने पर क्या होगा?
console.log( "sample b" ); b(); function b() { console.log(1); }
सही - उदाहरण के नाम के साथ पाठ पहले कंसोल में दिखाई देगा, और फिर एक, क्योंकि सभी नामित फ़ंक्शन गुंजाइश की शुरुआत में स्थानांतरित किए जाते हैं, और आप उन्हें कभी भी कॉल कर सकते हैं।
हम कार्य को जटिल करते हैं
console.log( "sample c" ); function c() { console.log(1); } c(); function c() { console.log(2); }
लेकिन हमें भ्रमित न करना बहुत आसान है। कार्य शुरू में उसी क्रम में स्थानांतरित किए जाते हैं जिसमें वे बनाए गए थे, अर्थात्, कंसोल में 2 होंगे।
ठीक है ना?
console.log( "sample d" ); d(); var d = function() { console.log(2); }
उत्तर: और यहां नियम अलग हैं - यह बिल्कुल भी काम नहीं करेगा, क्योंकि कॉल के समय चर का मूल्य अपरिभाषित है।
और अगर ऐसा है तो?
console.log( "sample e" ); var e = function(){ console.log(1); } e(); e = function() { console.log(2); }
खैर, यहां सब कुछ पहले से ही स्पष्ट है, हां - कॉल के समय,
ई में पहला फ़ंक्शन होता है, इसलिए कंसोल में एक होगा।
और अब यह सबसे कठिन प्रश्न * ड्रम रोल * का समय है
यहां क्या होगा?
console.log( "sample f" ); var f = function() { console.log(1); } f(); function f(){ console.log(2); } f();
सही उत्तर: दो बार एक। उनकी घोषणा के बाद, चर कार्यों को ओवरलैप करते हैं।
हमेशा।
तत्काल कार्य
इस नाम के पीछे "वन-टाइम" फ़ंक्शन हैं - उनके पास कोई नाम नहीं है, और उनकी घोषणा के तुरंत बाद निष्पादित किया जाता है।
इसकी आवश्यकता क्यों है? अधिकांश भाग के लिए, वैश्विक नामस्थान को रोकना नहीं है। उदाहरण के लिए, यदि आपको किसी चीज़ को इनिशियलाइज़ करना है, और इनिशियलाइज़ेशन के दौरान, हमें कुछ ऐसे वेरिएबल्स की ज़रूरत है जो तब पूरी तरह से अनावश्यक हों।
आप इस तरह के एक समारोह को दो अनिवार्य रूप से समकक्ष तरीके से घोषित कर सकते हैं।
console.log("//immidiate function"); //sample a (function(){ console.log( "a" ); })(); //sample b (function(){ console.log( "b" ); }());
उनके बीच कोई मतभेद नहीं हैं।
इनिट टाइम ब्रांचिंग
कभी-कभी ऐसा होता है कि किसी फ़ंक्शन का मान कुछ मान पर निर्भर करता है, जो कि आरंभीकरण के बाद नहीं बदलता है। कुछ इस तरह से:
// function saySomethingClever(){ var appleTest = /Apple/i; var googleTest = /Google/i; if( appleTest.test(navigator.vendor) ) console.log("I love apples <3") else if( googleTest.test(navigator.vendor) ) console.log("android is everything for me <3") else console.log("i love this unpopular corporation too") } saySomethingClever();
सब कुछ बहुत अच्छा है, सिवाय इसके कि हर बार हम कॉल करते हैं, हम एक चेक बनाते हैं जो बिल्कुल अनावश्यक हो गया है। आप इस तरह से फ़ंक्शन को फिर से लिख सकते हैं:
// var saySomethingClever = (function(){ var appleTest = /Apple/i; var googleTest = /Google/i; if( appleTest.test(navigator.vendor) ) return function(){ console.log("I love apples <3"); } if( googleTest.test(navigator.vendor) ) return function(){ console.log("android is everything for me <3"); } return function(){ console.log("i love this unpopular corporation too"); } })(); saySomethingClever();
जैसा कि एक चौकस पाठक ने देखा होगा,
अपरिपक्व फ़ंक्शन का उपयोग यहां भी किया जाता है। अब जाँच बिलकुल एक बार की जाती है।
स्वयं को परिभाषित करने का कार्य
कभी-कभी ऐसा होता है कि जब आप पहली बार किसी फ़ंक्शन को कॉल करते हैं, तो आपको कुछ अतिरिक्त क्रियाएं करने की आवश्यकता होती है। आप इसे इस प्रकार लागू कर सकते हैं:
var selfDefining = function() { console.log("some really heavy initialization occured"); console.log("f*ck yeah!"); selfDefining = function(){ console.log("job done!"); } } selfDefining(); selfDefining();
यह तकनीक फ़ंक्शन के बाहर एक चर को बचाने में मदद करती है, जिसके द्वारा हम जांचेंगे कि फ़ंक्शन को बुलाया गया था या नहीं।
Currying
इस तकनीक का उपयोग करके, आप कुछ सामान्य कार्य का एक निजी संस्करण बना सकते हैं। कार्यान्वयन इस तरह दिखता है:
function curry( fn ){ var slice = Array.prototype.slice, storedArgs = slice.call( arguments, 1 ); return function() { var args = storedArgs.concat( slice.call( arguments ) ); return fn.apply( this, args ); } }
हालांकि निफ्गा समझ से बाहर है, लेकिन यह सामान्य है। मैं अब सब कुछ समझाता हूँ।
मान लीजिए हमारे पास एक फ़ंक्शन है जो एक संदेश प्रिंट करता है।
function printMessage( author, message ){ console.log( author + " say: " + message ) }
लेकिन परियोजना के इस मॉड्यूल में,
मुझे हमेशा लेखक के मूल्य के रूप में उपयोग किया जाता है, इसलिए इसका एक अधिक निजी संस्करण जो एक संदेश के साथ केवल एक पंक्ति को स्वीकार करता है, और खुद लेखक को लिखता है, बहुत वांछनीय है।
var printMyMessage = curry( printMessage, "me" )
और अब हमारे पास है।
युपीडी। उपनाम
जामायका के साथ एक बहुत अच्छे व्यक्ति से लेख को
जोड़नापुनरावर्ती कार्यों की घोषणा करें
उदाहरण के लिए, हमारे पास एक बेवकूफ गुट है जो कोड के ढेर में उपयोग किया जाता है:
var factorial = function (n) { return n === 1 ? 1 : factorial(n - 1) * n; };
अच्छी तरह से या
function factorial(n) { return n === 1 ? 1 : factorial(n - 1) * n; };
फिर किसी कारण से हमें चाहिए
var realFactorial = factorial; factorial = function (n) { throw 'please use realFactorial instead'; };
नतीजतन, यह पता चलता है कि फैक्टरियल (5) और रियलफैक्टीरियल (5) को कॉल करने से त्रुटि होती है। इस कारण प्राप्त किया जाता है पुनरावर्ती कॉल फैक्टरियल पैरेंट स्कोप से एक वैरिएबल का उपयोग करता है, और वहां इसे फिर से परिभाषित किया जाता है। इस मामले में, आपको फ़ंक्शन को इस तरह परिभाषित करने की आवश्यकता है:
var factorial = function factorial (n) { return n === 1 ? 1 : factorial(n - 1) * n; };
ठीक है, या भ्रमित होने की नहीं:
var factorial = function f (n) { return n === 1 ? 1 : f(n - 1) * n; };
ऐसा लगता है कि सभी - हमेशा की तरह, उदाहरण के लिए स्रोत कोड
यहां डाउनलोड किया जा सकता
है