एकाधिक तर्क बनाम विकल्प वस्तु


157

कई तर्कों के साथ जावास्क्रिप्ट फ़ंक्शन बनाते समय, मैं हमेशा इस पसंद से सामना करता हूं: तर्कों की एक सूची पास करें बनाम एक विकल्प ऑब्जेक्ट पास करें।

उदाहरण के लिए, मैं एक सरणी में एक नोडलिस्ट को मैप करने के लिए एक फ़ंक्शन लिख रहा हूं:

function map(nodeList, callback, thisObject, fromIndex, toIndex){
    ...
}

मैं इसके बजाय इसका उपयोग कर सकता हूं:

function map(options){
    ...
}

जहाँ विकल्प एक वस्तु है:

options={
    nodeList:...,
    callback:...,
    thisObject:...,
    fromIndex:...,
    toIndex:...
}

अनुशंसित तरीका कौन सा है? क्या एक बनाम दूसरे का उपयोग करने के लिए दिशानिर्देश हैं?

[अपडेट] विकल्प ऑब्जेक्ट के पक्ष में एक आम सहमति प्रतीत होती है, इसलिए मैं एक टिप्पणी जोड़ना चाहूंगा: एक कारण है कि मुझे अपने मामले में तर्कों की सूची का उपयोग करने के लिए लुभाया गया था, जो कि जावास्क्रिप्ट के अनुरूप व्यवहार था array.map विधि में बनाया गया है।


2
दूसरा विकल्प आपको नामांकित तर्क देता है, जो मेरी राय में एक अच्छी बात है।
वर्नर क्वालाम वेस्टरस

क्या वे वैकल्पिक या आवश्यक तर्क हैं?
मुझे हेट लेजी

@ user1689607 मेरे उदाहरण में अंतिम तीन वैकल्पिक हैं।
क्रिस्टोफ़

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

1
देशी एपीआई के बाद मॉडलिंग करना कोई बुरी बात नहीं है, यदि आपका कार्य कुछ इसी तरह का है। यह सब "कोड को सबसे अधिक पढ़ा जाने वाला" बनाता है। Array.prototype.mapएक साधारण एपीआई है जो किसी भी अर्ध-अनुभवी कोडर को ऊपर नहीं छोड़ना चाहिए।
जेरेमी जे स्टारचेर

जवाबों:


160

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

मैं लिटमस टेस्ट के रूप में कोड पठनीयता का उपयोग करता हूं।

उदाहरण के लिए, अगर मेरे पास यह फ़ंक्शन कॉल है:

checkStringLength(inputStr, 10);

मुझे लगता है कि कोड काफी पठनीय है जिस तरह से यह है और व्यक्तिगत मापदंडों को पारित करना ठीक है।

दूसरी ओर, इस तरह के कॉल के साथ कार्य हैं:

initiateTransferProtocol("http", false, 150, 90, null, true, 18);

पूरी तरह से अपठनीय जब तक आप कुछ शोध नहीं करते हैं। दूसरी ओर, यह कोड अच्छी तरह से पढ़ता है:

initiateTransferProtocol({
  "protocol": "http",
  "sync":      false,
  "delayBetweenRetries": 150,
  "randomVarianceBetweenRetries": 90,
  "retryCallback": null,
  "log": true,
  "maxRetries": 18
 });

यह एक विज्ञान की तुलना में अधिक कला है, लेकिन अगर मुझे अंगूठे के नियमों का नाम देना है:

एक विकल्प पैरामीटर का उपयोग करें यदि:

  • आपके पास चार से अधिक पैरामीटर हैं
  • कोई भी पैरामीटर वैकल्पिक है
  • आपको कभी यह देखने के लिए फ़ंक्शन को देखना होगा कि यह कौन से पैरामीटर लेता है
  • अगर कोई कभी "ARRRRRG" चिल्लाते हुए आपका गला घोंटने की कोशिश करता है!

10
बहुत बढ़िया जवाब। निर्भर करता है। खबरदार बुलियन ट्रैप्स ariya.ofilabs.com/2011/08/hall-of-api-shame-boolean-trap.html
ट्रेवर डिक्सन

2
अरे हाँ ... मैं उस लिंक के बारे में भूल गया था। इसने मुझे वास्तव में पुनर्विचार करने के लिए प्रेरित किया कि एपीआई कैसे काम करती है और मैंने यह जानने के बाद कि मैंने गूंगी चीजें सीखीं, कोड के कई टुकड़े फिर से लिख दिए। धन्यवाद!
जेरेमी जे स्टारचेर

1
'आपको कभी यह देखने के लिए फ़ंक्शन को देखना पड़ता है कि कौन से पैरामीटर लगते हैं' - इसके बजाय एक विकल्प ऑब्जेक्ट का उपयोग करते हुए, आपको हमेशा यह पता लगाने की विधि नहीं दिखानी होगी कि कुंजी की आवश्यकता है और उन्हें क्या कहा जाता है। IDE में Intellisense इस जानकारी को नहीं रखता है, जबकि params करते हैं। अधिकांश IDEs में, आप बस इस विधि पर माउस को मँडरा सकते हैं और यह आपको दिखाएगा कि परमेस क्या हैं।
प्रतीकबो

1
यदि y'all 'सर्वोत्तम प्रथाओं के कोडन' के इस बिट के प्रदर्शन के परिणामों में रुचि रखते हैं, तो यहां एक jsPerf दोनों तरीकों का परीक्षण किया गया है: jsperf.com/function-boolean-arguments-vs-options-obit/10 थोड़ा ट्विस्ट नोट करें। तीसरा विकल्प, जहां मैं एक 'प्रीसेट' (स्थिर) विकल्प ऑब्जेक्ट का उपयोग करता हूं, जिसे तब किया जा सकता है जब आप एक ही सेटिंग्स के साथ कई कॉल, जैसे कि आपके वेबपेज), विकास के समय में जाना जाता है (संक्षेप में : जब आपके विकल्प मान थोड़े स्रोतकोड में हार्डकोड किए जाते हैं)।
गेर हॉबेल्ट ने

2
@ सीन ईमानदारी से कहूं तो मैं अब कोडिंग की इस शैली का बिल्कुल भी उपयोग नहीं करता हूं। मैंने टाइपस्क्रिप्ट पर नामांकित किया है और नामित मापदंडों का उपयोग किया है।
जेरेमी जे स्टारचर

28

कई तर्क ज्यादातर अनिवार्य मापदंडों के लिए हैं। उनके साथ कुछ भी गलत नहीं है

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

विकल्प वस्तुएं दो मामलों में काम आती हैं:

  • आपके पास इतने सारे पैरामीटर हैं कि यह भ्रमित हो जाता है: "नामकरण" आपकी मदद करेगा, आपको उनके आदेश के बारे में चिंता करने की ज़रूरत नहीं है (विशेषकर यदि वे बदल सकते हैं)
  • आपको वैकल्पिक पैरामीटर मिले हैं। वस्तुएं बहुत लचीली हैं, और बिना किसी आदेश के आप केवल उन चीजों को पास करते हैं जिनकी आपको आवश्यकता है और कुछ और (या undefinedएस)।

आपके मामले में, मैं सुझाऊंगा map(nodeList, callback, options)nodelistऔर callbackआवश्यकता है, अन्य तीन तर्क कभी-कभी ही आते हैं और उचित चूक होते हैं।

एक और उदाहरण है JSON.stringify। आप spaceएक replacerफ़ंक्शन पास किए बिना पैरामीटर का उपयोग करना चाह सकते हैं - फिर आपको कॉल करना होगा …, null, 4)। एक तर्क वस्तु बेहतर हो सकती है, हालांकि यह वास्तव में केवल 2 मापदंडों के लिए उचित नहीं है।


@ Trevor-dixon के समान +1 प्रश्न: क्या आपने इस मिश्रण को अभ्यास के लिए उपयोग किया है, उदाहरण के लिए js पुस्तकालयों में?
क्रिस्टोफ

एक उदाहरण jQuery के ajax तरीके हो सकते हैं । वे पहले तर्क के रूप में [अनिवार्य] URL और दूसरे के रूप में एक विशाल विकल्प तर्क स्वीकार करते हैं।
बरगी

बहुत अजीब! मैंने पहले कभी इस पर ध्यान नहीं दिया। मैंने हमेशा इसे url के साथ एक विकल्प संपत्ति के रूप में देखा है ...
Christophe

हाँ, jQuery अपने वैकल्पिक मापदंडों के साथ अजीब बात करता है जबकि पीछे की ओर संगत रहता है :-)
बर्गी

1
मेरी राय में, यह यहाँ एकमात्र एकमात्र जवाब है।
बेंजामिन Gruenbaum

11

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

एक वस्तु बनाने का अर्थ यह भी है कि विकल्प कई कार्यों पर आसानी से उपयोग किए जा सकते हैं:

options={
    nodeList:...,
    callback:...,
    thisObject:...,
    fromIndex:...,
    toIndex:...
}

function1(options){
    alert(options.nodeList);
}

function2(options){
    alert(options.fromIndex);
}

यहाँ (उचित) धारणा यह है कि वस्तु में हमेशा एक ही कुंजी जोड़े होंगे। यदि आप एक बकवास / असंगत एपीआई के साथ काम कर रहे हैं तो आपके हाथों पर एक अलग समस्या है।
बैकडेस्क

9

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

कुछ मामलों में, दोनों का उपयोग करना अच्छा है। यदि आपके फ़ंक्शन में एक या दो आवश्यक पैरामीटर और वैकल्पिक लोगों का एक गुच्छा है, तो पहले दो पैरामीटर आवश्यक करें और तीसरा एक वैकल्पिक विकल्प हैश।

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


+1 दिलचस्प। क्या आपने इसे अभ्यास में उपयोग करते हुए देखा है, उदाहरण के लिए js पुस्तकालयों में?
क्रिस्टोफ

7

प्रश्न पर आपकी टिप्पणी:

मेरे उदाहरण में अंतिम तीन वैकल्पिक हैं।

तो ऐसा क्यों नहीं करते? (नोट: यह काफी कच्चा जावास्क्रिप्ट है। आम तौर पर मैं एक defaultहैश का उपयोग करता हूँ और Object.extend या JQuery.extend या समान .. का उपयोग करके पारित विकल्पों के साथ इसे अपडेट करता हूं ।)

function map(nodeList, callback, options) {
   options = options || {};
   var thisObject = options.thisObject || {};
   var fromIndex = options.fromIndex || 0;
   var toIndex = options.toIndex || 0;
}

इसलिए, अब चूंकि यह अब और अधिक स्पष्ट है कि वैकल्पिक क्या है और क्या नहीं है, ये सभी फ़ंक्शन के मान्य उपयोग हैं:

map(nodeList, callback);
map(nodeList, callback, {});
map(nodeList, callback, null);
map(nodeList, callback, {
   thisObject: {some: 'object'},
});
map(nodeList, callback, {
   toIndex: 100,
});
map(nodeList, callback, {
   thisObject: {some: 'object'},
   fromIndex: 0,
   toIndex: 100,
});

यह @ trevor-dixon के उत्तर के समान है।
क्रिस्टोफ

5

मुझे इस प्रतिक्रिया के साथ पार्टी में थोड़ी देर हो सकती है, लेकिन मैं इस विषय पर अन्य डेवलपर्स की राय खोज रहा था और इस धागे के पार आया।

मैं अधिकांश उत्तरदाताओं से असहमत हूं, और 'कई तर्कों' के साथ पक्ष रखता हूं। मेरा मुख्य तर्क यह है कि यह अन्य विरोधी प्रतिमानों को हतोत्साहित करता है जैसे "परम ऑब्जेक्ट को म्यूट करना और वापस करना", या "अन्य कार्यों पर उसी परम ऑब्जेक्ट को पास करना"। मैंने कोडबेस में काम किया है जिसने इस विरोधी पैटर्न का व्यापक रूप से दुरुपयोग किया है, और कोडिंग डिबगिंग जो यह जल्दी से असंभव हो जाता है। मुझे लगता है कि यह अंगूठे का एक बहुत विशिष्ट-विशिष्ट नियम है, क्योंकि जावास्क्रिप्ट को दृढ़ता से टाइप नहीं किया जाता है और ऐसी मनमाने ढंग से संरचित वस्तुओं के लिए अनुमति देता है।

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

निम्नलिखित भयानक कोड पर विचार करें:

function main() {
    const x = foo({
        param1: "something",
        param2: "something else",
        param3: "more variables"
    });

    return x;
}

function foo(params) {
    params.param1 = "Something new";
    bar(params);
    return params;
}


function bar(params) {
    params.param2 = "Something else entirely";
    const y = baz(params);
    return params.param2;
}

function baz(params) {
    params.params3 = "Changed my mind";
    return params;
}

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

मुद्दे पर सिर्फ मेरे दो-सेंट!


3

निर्भर करता है।

उन लोकप्रिय पुस्तकालयों के डिजाइन पर मेरे अवलोकन के आधार पर, यहां वे परिदृश्य हैं जो हमें विकल्प ऑब्जेक्ट का उपयोग करना चाहिए:

  • पैरामीटर सूची लंबी (> 4) है।
  • कुछ या सभी पैरामीटर वैकल्पिक हैं और वे एक निश्चित क्रम पर भरोसा नहीं करते हैं।
  • पैरामीटर सूची भविष्य के एपीआई अपडेट में बढ़ सकती है।
  • एपीआई को अन्य कोड से बुलाया जाएगा और पैरामीटर का अर्थ बताने के लिए एपीआई नाम पर्याप्त स्पष्ट नहीं है। तो यह पठनीयता के लिए मजबूत पैरामीटर नाम की आवश्यकता हो सकती है।

और पैरामीटर सूची का उपयोग करने के लिए परिदृश्य:

  • पैरामीटर सूची कम है (<= 4)।
  • अधिकांश या सभी मापदंडों की आवश्यकता होती है।
  • वैकल्पिक पैरामीटर एक निश्चित क्रम में हैं। (यानी: $ .get)
  • एपीआई नाम से मापदंडों का अर्थ बताना आसान है।

2

ऑब्जेक्ट अधिक बेहतर है, क्योंकि यदि आप किसी ऑब्जेक्ट को उस ऑब्जेक्ट में गुणों की संख्या को बढ़ाने के लिए आसान पास करते हैं और आपको उस क्रम के लिए देखने की ज़रूरत नहीं है जिसमें आपके तर्क पारित किए गए हैं।


1

एक फ़ंक्शन के लिए जो आमतौर पर कुछ पूर्वनिर्धारित तर्कों का उपयोग करता है आप बेहतर विकल्प ऑब्जेक्ट का उपयोग करेंगे। विपरीत उदाहरण एक फ़ंक्शन की तरह होगा जो अनंत तर्क प्राप्त कर रहा है जैसे: setCSS ({ऊँचाई: 100}, {चौड़ाई: 200}, {पृष्ठभूमि: "# 000"})।


0

मैं बड़ी जावास्क्रिप्ट परियोजनाओं को देखूंगा।

Google मानचित्र जैसी चीजें आप अक्सर देखेंगे कि तात्कालिक वस्तुओं को एक वस्तु की आवश्यकता होती है, लेकिन कार्यों के लिए मापदंडों की आवश्यकता होती है। मुझे लगता है कि यह विकल्प argumemnts के साथ करना होगा।

यदि आपको डिफ़ॉल्ट तर्क या वैकल्पिक तर्क की आवश्यकता है तो एक वस्तु शायद बेहतर होगी क्योंकि यह अधिक लचीला है। लेकिन अगर आप सामान्य कार्यात्मक तर्क नहीं देते हैं तो अधिक स्पष्ट हैं।

जावास्क्रिप्ट भी एक argumentsवस्तु है। https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments

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