इस जावास्क्रिप्ट पैटर्न को क्या कहा जाता है और इसका उपयोग क्यों किया जाता है?


100

मैं THREE.js का अध्ययन कर रहा हूं और एक ऐसा पैटर्न देखा है जहां फ़ंक्शन को इस तरह परिभाषित किया जाता है:

var foo = ( function () {
    var bar = new Bar();

    return function ( ) {
        //actual logic using bar from above.
        //return result;
    };
}());

(उदाहरण देखें यहां रेकास्ट विधि )।

इस तरह की विधि की सामान्य भिन्नता इस तरह दिखाई देगी:

var foo = function () {
    var bar = new Bar();

    //actual logic.
    //return result;
};

पहले संस्करण की तुलना सामान्य भिन्नता से की जाती है, पहला ऐसा लगता है:

  1. यह एक स्व-निष्पादित फ़ंक्शन का परिणाम प्रदान करता है।
  2. यह इस फ़ंक्शन के भीतर एक स्थानीय चर को परिभाषित करता है।
  3. यह तर्क युक्त वास्तविक फ़ंक्शन को लौटाता है जो स्थानीय चर का उपयोग करता है।

इसलिए मुख्य अंतर यह है कि पहले बदलाव में बार को केवल एक बार सौंपा जाता है, आरंभीकरण पर, जबकि दूसरा भिन्नता इस अस्थायी चर को हर बार बनाता है जब इसे कहा जाता है।

यह क्यों उपयोग किया जाता है, इस पर मेरा सबसे अच्छा अनुमान यह है कि यह बार के लिए उदाहरणों की संख्या को सीमित करता है (केवल एक ही होगा) और इस प्रकार मेमोरी मैनेजमेंट हेडहेड को बचाता है।

मेरे सवाल:

  1. क्या यह धारणा सही है?
  2. क्या इस पैटर्न का कोई नाम है?
  3. इसका उपयोग क्यों किया जाता है?

1
@ChrisHayes काफी निष्पक्ष। मैंने इसे THREE.js के रूप में टैग किया क्योंकि मुझे लगा कि THREE.js योगदानकर्ता इसका उत्तर देने के लिए सबसे योग्य हैं, लेकिन हाँ, यह एक सामान्य जेएस प्रश्न है।
पैट्रिक क्लग

2
मेरा मानना ​​है कि इसे क्लोजर कहा जाता है। आप उनके बारे में पढ़ सकते हैं।
ढेर हुए

1
यदि यह एकमात्र स्थान है जहां एक बार त्वरित है, तो यह एक सिंगलटन पैटर्न है।
पॉल

8
स्मृति को बचाने के लिए आवश्यक नहीं है, लेकिन यह आक्रमण के दौरान राज्य को बनाए रख सकता है
जुआन मेंडेस

2
@wrongAnswer: बिल्कुल नहीं। यहाँ अनाम फ़ंक्शन (जो बंद होगा) को तुरंत निष्पादित किया जाता है।
njzk2

जवाबों:


100

आपकी धारणाएँ लगभग सही हैं। आइए पहले उन की समीक्षा करें।

  1. यह एक स्व-निष्पादित फ़ंक्शन की वापसी प्रदान करता है

इसे तत्काल-आमंत्रित फ़ंक्शन अभिव्यक्ति या IIFE कहा जाता है

  1. यह इस फ़ंक्शन के भीतर एक स्थानीय चर को परिभाषित करता है

यह जावास्क्रिप्ट में निजी ऑब्जेक्ट फ़ील्ड होने का तरीका है क्योंकि यह privateकीवर्ड या कार्यक्षमता प्रदान नहीं करता है ।

  1. यह तर्क युक्त वास्तविक फ़ंक्शन को लौटाता है जो स्थानीय चर का उपयोग करता है।

फिर, मुख्य बिंदु यह है कि यह स्थानीय चर निजी है

क्या इस पैटर्न का कोई नाम है?

AFAIK आप इस पैटर्न को मॉड्यूल पैटर्न कह सकते हैं । का हवाला देते हुए:

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

उन दो उदाहरणों की तुलना करते हुए, मेरा सबसे अच्छा अनुमान इस बात पर है कि पहले एक का उपयोग क्यों किया जाता है:

  1. यह सिंगलटन डिजाइन पैटर्न को लागू कर रहा है।
  2. पहला उदाहरण का उपयोग करके किसी विशिष्ट प्रकार की वस्तु को बनाया जा सकता है। इस बिंदु के साथ एक करीबी मैच प्रभावी कारखाने के तरीके हो सकते हैं जैसा कि प्रभावी जावा में वर्णित है।
  3. यदि आप हर बार एक ही वस्तु स्थिति की आवश्यकता है तो यह कुशल है

लेकिन अगर आपको हर बार केवल वेनिला ऑब्जेक्ट की आवश्यकता होती है, तो यह पैटर्न शायद कोई मूल्य नहीं जोड़ेगा।


1
Addy Osmani की पुस्तक से पैटर्न की सही पहचान के लिए +1। आप अपने नामकरण में सही हैं - यह वास्तव में मॉड्यूल पैटर्न है - जिस तरह से खुलासा मॉड्यूल पैटर्न।
बेंजामिन ग्रुएनबाउम

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

मुझे लगता है कि "निजी चर" से, आपका मतलब निजी "वस्तु क्षेत्र" से था
इयान रिंगरोज 18


4
@LukaHorvat: तथ्य के रूप में, जावास्क्रिप्ट अन्य भाषाओं की तुलना में अधिक "शक्तिशाली" नहीं है (मैं अभिव्यंजक शब्द को पसंद करता हूं)। वास्तव में, यह कम अभिव्यंजक है, क्योंकि आपके चर की रक्षा करने का एकमात्र तरीका किसी भी चर-पुन: उपयोग बकवास से बचने के लिए फ़ंक्शन में संलग्न है। मॉड्यूल पैटर्न अच्छा जावास्क्रिप्ट कोड बनाने के लिए एक निश्चित आवश्यकता है, लेकिन यह भाषा की एक विशेषता नहीं है, यह भाषा की कमजोरियों से काटे जाने से बचने के लिए एक दु: खद काम है।
फलांवे

11

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

हालांकि यह संभव है कि यह मेमोरी के उपयोग को सीमित करता है, आमतौर पर जीसी अप्रयुक्त वस्तुओं को किसी भी तरह इकट्ठा करेगा, इसलिए इस पैटर्न से बहुत मदद मिलने की संभावना नहीं है।

यह पैटर्न क्लोजर का एक विशिष्ट रूप है ।


1
जे एस में यह आम तौर पर के रूप में 'मॉड्यूल' reffers है
Lesha Ogonkov

2
मैं इसे "बंद करने का एक विशिष्ट रूप" नहीं कहूंगा, प्रति से। यह एक पैटर्न है जो एक क्लोजर का उपयोग करता है। पैटर्न का नाम अभी भी कब्रों के लिए है।
क्रिस हेस

4
क्या इसे वास्तव में एक नाम की आवश्यकता है? क्या हर चीज का एक पैटर्न होना चाहिए? क्या हमें वास्तव में "मॉड्यूल पैटर्न" वेरिएंट की अंतहीन वर्गीकरण की आवश्यकता है? क्या यह "कुछ स्थानीय चर के साथ एक IIFE नहीं हो सकता है जो एक फ़ंक्शन देता है?"
डग नबबिट सेप

3
@DaggNabbit जब सवाल है "इस पैटर्न को क्या कहा जाता है"? हां, इसे एक नाम की आवश्यकता है या फिर एक ठोस तर्क है कि यह एक नहीं है। इसके अलावा, पैटर्न एक कारण से मौजूद हैं। मुझे समझ नहीं आ रहा है कि आप यहाँ उनके खिलाफ रेलिंग क्यों कर रहे हैं।
क्रिस हेस

4
@ChrisHayes अगर इसे एक नाम की आवश्यकता है, तो आपको एक तर्क देने की आवश्यकता क्यों होगी कि यह एक नहीं है? इसका कोई मतलब नहीं है। यदि इसे एक की आवश्यकता है, तो इसके पास एक नहीं होना चाहिए। मुझे पैटर्न के साथ कोई समस्या नहीं है, लेकिन मुझे नहीं लगता कि पैटर्न के रूप में हर एक सरल मुहावरे को वर्गीकृत करना आवश्यक है। ऐसा करने से सीमित तरीके से सोचने लगते हैं ("क्या यह एक मॉड्यूल पैटर्न है? क्या मैं मॉड्यूल पैटर्न का सही तरीके से उपयोग कर रहा हूं?" बनाम "मेरे पास कुछ स्थानीय चर के साथ एक IIFE है जो एक फ़ंक्शन देता है, क्या यह डिज़ाइन मेरे लिए काम करता है?")
डग नबबिट सेप

8

मुझे यकीन नहीं है कि अगर इस पैटर्न का अधिक सही नाम है, लेकिन यह मेरे लिए एक मॉड्यूल की तरह दिखता है, और इसका उपयोग करने का कारण दोनों को संक्षिप्त करना और राज्य बनाए रखना है।

क्लोजर (किसी फ़ंक्शन के भीतर एक फ़ंक्शन द्वारा पहचाना गया) यह सुनिश्चित करता है कि आंतरिक फ़ंक्शन बाहरी फ़ंक्शन के भीतर चर तक पहुंच है।

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


5

आपके कोड और थ्री.जेएस कोड के बीच मुख्य अंतर यह है कि थ्री.जेएस कोड में वैरिएबल tmpObjectको केवल एक बार आरंभीकृत किया जाता है, और फिर लौटाए गए फ़ंक्शन के प्रत्येक इनवोकेशन द्वारा साझा किया जाता है।

यह कॉल के बीच कुछ स्थिति रखने के लिए उपयोगी होगा, इसी तरह staticसी-लाइक भाषाओं में चर का उपयोग कैसे किया जाता है।

tmpObject एक निजी चर है जो केवल आंतरिक फ़ंक्शन को दिखाई देता है।

यह मेमोरी उपयोग को बदलता है, लेकिन इसकी मेमोरी को बचाने के लिए डिज़ाइन नहीं किया गया है।


5

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

यहां छवि विवरण दर्ज करें

बाद के मामले में, जोड़ विधि कैलकुलेटर के रूप में कहा जाएगा।


0

दिए गए उदाहरण में, पहला स्निपेट फ़ंक्शन कॉल फू () के लिए हर कॉल के लिए tmpObject का एक ही उदाहरण का उपयोग करेगा, जहां दूसरे स्निपेट में, tmpObject हर बार एक नया उदाहरण होगा।

पहला स्निपेट इस्तेमाल होने का एक कारण यह भी हो सकता है कि वेरिएबल tmpObject को कॉल्स के बीच में फू () में शेयर किया जा सकता है, बिना इसके वैल्यू को उस स्कोप में लीक हुए फूक () में घोषित किया जाता है।

पहले स्निपेट के गैर-तुरंत निष्पादित फ़ंक्शन संस्करण वास्तव में इस तरह दिखाई देंगे:

var tmpObject = new Bar();

function foo(){
    // Use tmpObject.
}

ध्यान दें कि इस संस्करण में foo () के समान स्कोप में tmpObject है, इसलिए इसे बाद में हेरफेर किया जा सकता है।

एक ही कार्यक्षमता प्राप्त करने का एक बेहतर तरीका एक अलग मॉड्यूल का उपयोग करना होगा:

मॉड्यूल 'foo.js':

var tmpObject = new Bar();

module.exports = function foo(){
    // Use tmpObject.
};

मॉड्यूल 2:

var foo = require('./foo');

एक IEF और एक नामित फू निर्माता समारोह के प्रदर्शन के बीच एक तुलना: http://jsperf.com/ief-vs-n-


3
आपका 'बेहतर' उदाहरण केवल NodeJS में काम करता है और आपने यह नहीं बताया कि यह कैसे बेहतर है।
बेंजामिन Gruenbaum

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

@BenjaminGruenbaum मॉड्यूल केवल नोड में नहीं हैं, कई क्लाइंट-साइड मॉड्यूल समाधान हैं, उदाहरण के लिए, ब्राउज़र करें। मैं मॉड्यूल समाधान को "बेहतर" मानता हूं क्योंकि यह अधिक पठनीय है, डिबग करना आसान है, और गुंजाइश में क्या है, और कहां है, इसके बारे में अधिक स्पष्ट है।
कोरी नूनन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.