जावास्क्रिप्ट में वैकल्पिक मापदंडों को संभालना


127

मेरे पास एक स्थिर जावास्क्रिप्ट फ़ंक्शन है जो 1, 2 या 3 पैरामीटर ले सकता है:

function getData(id, parameters, callback) //parameters (associative array) and callback (function) are optional

मुझे पता है कि मैं हमेशा परीक्षण कर सकता हूं कि किसी दिए गए पैरामीटर को अपरिभाषित किया गया है, लेकिन मुझे कैसे पता चलेगा कि क्या पारित किया गया था जो पैरामीटर या कॉलबैक था?

ऐसा करने का सबसे अच्छा तरीका क्या है?


क्या पारित किया जा सकता है इसके उदाहरण:

1:

getData('offers');

2:

var array = new Array();
array['type']='lalal';
getData('offers',array);

3:

var foo = function (){...}
getData('offers',foo);

4:

getData('offers',array,foo);

2
क्या आप एक उदाहरण दिखा सकते हैं कि इसमें क्या पारित किया जा सकता है?
जेम्स ब्लैक

जवाबों:


163

आप कितने जान सकते हैं आपके फ़ंक्शन में तर्क दिए गए थे और आप जांच सकते हैं कि आपका दूसरा तर्क फ़ंक्शन है या नहीं:

function getData (id, parameters, callback) {
  if (arguments.length == 2) { // if only two arguments were supplied
    if (Object.prototype.toString.call(parameters) == "[object Function]") {
      callback = parameters; 
    }
  }
  //...
}

आप इस तरह से तर्कों का उपयोग कर सकते हैं:

function getData (/*id, parameters, callback*/) {
  var id = arguments[0], parameters, callback;

  if (arguments.length == 2) { // only two arguments supplied
    if (Object.prototype.toString.call(arguments[1]) == "[object Function]") {
      callback = arguments[1]; // if is a function, set as 'callback'
    } else {
      parameters = arguments[1]; // if not a function, set as 'parameters'
    }
  } else if (arguments.length == 3) { // three arguments supplied
      parameters = arguments[1];
      callback = arguments[2];
  }
  //...
}

यदि आप रुचि रखते हैं, तो जावास्क्रिप्ट पर विधि अधिभार को अनुकरण करने की तकनीक के बारे में, जॉन रेसिग द्वारा इस लेख को देखें


क्यों Object.prototype.toString.call (पैरामीटर) == "[ऑब्जेक्ट फ़ंक्शन]" और टाइपऑफ़ (पैरामीटर) === 'फ़ंक्शन' का उपयोग क्यों करें? क्या उनके बीच कुछ महत्वपूर्ण अंतर है? PS आपके द्वारा
उल्लिखित

@TomerCagan मुझे लगता है कि यह वरीयता (ईश) की बात है। इस प्रश्न के अंतर्गत विषय पर कुछ अच्छे उत्तर / टिप्पणियाँ हैं ।
फिलीइआइआइआइपी

75

एर - इसका मतलब यह होगा कि आप अपने कार्य को उन तर्कों के साथ लागू कर रहे हैं, जो उचित क्रम में नहीं हैं ... जिसकी मैं सिफारिश नहीं करूँगा।

मैं आपके फ़ंक्शन को एक वस्तु खिलाने के बजाय ऐसा करने की सलाह दूंगा:

function getData( props ) {
    props = props || {};
    props.params = props.params || {};
    props.id = props.id || 1;
    props.callback = props.callback || function(){};
    alert( props.callback )
};

getData( {
    id: 3,
    callback: function(){ alert('hi'); }
} );

लाभ:

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

कमियां:

  • रिफैक्टर कोड का समय

यदि आपके पास कोई विकल्प नहीं है, तो आप यह पता लगाने के लिए फ़ंक्शन का उपयोग कर सकते हैं कि क्या कोई वस्तु वास्तव में एक फ़ंक्शन है (अंतिम उदाहरण देखें)।

नोट: यह एक फ़ंक्शन का पता लगाने का उचित तरीका है:

function isFunction(obj) {
    return Object.prototype.toString.call(obj) === "[object Function]";
}

isFunction( function(){} )

"यह कुछ ES बग्स के कारण 99% काम करेगा।" क्या आप और अधिक व्याख्या कर सकते हैं? यह गलत क्यों हो सकता है?
जद।

मैंने फ़ंक्शन का पता लगाने के लिए सही कोड जोड़ा है। मेरा मानना ​​है कि बग यहाँ है: bugs.ecmascript.org/ticket/251
meder omuraliev

मैं आपको केवल एक वस्तु खिलाने का सुझाव दूंगा। यदि नहीं, तो CMS की विधि का उपयोग करें।
मध्यरात्रि 7:00

ओह ... लानत है ... बस एक ही विचार पोस्ट किया।
अर्निस लैप्सा

1
एक अन्य संभावित दोष अंतःकरण की कमी है। मैं इसे बहुत बड़ी बात नहीं मानता, लेकिन इस पर ध्यान दिया जाना चाहिए।
Edyn

2

तो यह निर्धारित करने के लिए टाइपोऑपर ऑपरेटर का उपयोग करें कि दूसरा पैरामीटर एक एरे या फ़ंक्शन है।

यह कुछ सुझाव दे सकता है: http://www.planetpdf.com/developer/article.asp?ContentID=testing_for_object_types_in_ja

मैं निश्चित नहीं हूं कि यह काम है या होमवर्क, इसलिए मैं आपको इसका जवाब फिलहाल नहीं देना चाहता, लेकिन टाइपो आपको इसे निर्धारित करने में मदद करेगा।


2

आपको प्राप्त मापदंडों के प्रकार की जांच करनी चाहिए। हो सकता है कि आप argumentsसरणी का उपयोग करें क्योंकि दूसरा पैरामीटर कभी-कभी 'पैरामीटर' हो सकता है और कभी-कभी 'कॉलबैक' हो सकता है और इसका नामकरण पैरामीटर भ्रामक हो सकता है।


2

मुझे पता है कि यह एक बहुत पुराना सवाल है, लेकिन मैंने हाल ही में इससे निपटा है। मुझे पता है कि आप इस समाधान के बारे में क्या सोचते हैं।

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

यह वही है जो कार्यान्वयन जैसा दिखता है:

function displayOverlay(/*message, timeout, callback*/) {
  return arrangeArgs(arguments, String, Number, Function, 
    function(message, timeout, callback) {
      /* ... your code ... */
    });
};

स्पष्टता के लिए, यहाँ क्या है:

function displayOverlay(/*message, timeout, callback*/) {
  //arrangeArgs is the proxy
  return arrangeArgs(
           //first pass in the original arguments
           arguments, 
           //then pass in the type for each argument
           String,  Number,  Function, 
           //lastly, pass in your function and the proxy will do the rest!
           function(message, timeout, callback) {

             //debug output of each argument to verify it's working
             console.log("message", message, "timeout", timeout, "callback", callback);

             /* ... your code ... */

           }
         );
};

आप यहाँ मेरे GitHub रिपॉजिटरी में अरेंजर्स प्रॉक्सी कोड को देख सकते हैं:

https://github.com/joelvh/Sysmo.js/blob/master/sysmo.js

यहाँ रिपॉजिटरी से कॉपी किए गए कुछ टिप्पणियों के साथ उपयोगिता फ़ंक्शन है:

/*
 ****** Overview ******
 * 
 * Strongly type a function's arguments to allow for any arguments to be optional.
 * 
 * Other resources:
 * http://ejohn.org/blog/javascript-method-overloading/
 * 
 ****** Example implementation ******
 * 
 * //all args are optional... will display overlay with default settings
 * var displayOverlay = function() {
 *   return Sysmo.optionalArgs(arguments, 
 *            String, [Number, false, 0], Function, 
 *            function(message, timeout, callback) {
 *              var overlay = new Overlay(message);
 *              overlay.timeout = timeout;
 *              overlay.display({onDisplayed: callback});
 *            });
 * }
 * 
 ****** Example function call ******
 * 
 * //the window.alert() function is the callback, message and timeout are not defined.
 * displayOverlay(alert);
 * 
 * //displays the overlay after 500 miliseconds, then alerts... message is not defined.
 * displayOverlay(500, alert);
 * 
 ****** Setup ******
 * 
 * arguments = the original arguments to the function defined in your javascript API.
 * config = describe the argument type
 *  - Class - specify the type (e.g. String, Number, Function, Array) 
 *  - [Class/function, boolean, default] - pass an array where the first value is a class or a function...
 *                                         The "boolean" indicates if the first value should be treated as a function.
 *                                         The "default" is an optional default value to use instead of undefined.
 * 
 */
arrangeArgs: function (/* arguments, config1 [, config2] , callback */) {
  //config format: [String, false, ''], [Number, false, 0], [Function, false, function(){}]
  //config doesn't need a default value.
  //config can also be classes instead of an array if not required and no default value.

  var configs = Sysmo.makeArray(arguments),
      values = Sysmo.makeArray(configs.shift()),
      callback = configs.pop(),
      args = [],
      done = function() {
        //add the proper number of arguments before adding remaining values
        if (!args.length) {
          args = Array(configs.length);
        }
        //fire callback with args and remaining values concatenated
        return callback.apply(null, args.concat(values));
      };

  //if there are not values to process, just fire callback
  if (!values.length) {
    return done();
  }

  //loop through configs to create more easily readable objects
  for (var i = 0; i < configs.length; i++) {

    var config = configs[i];

    //make sure there's a value
    if (values.length) {

      //type or validator function
      var fn = config[0] || config,
          //if config[1] is true, use fn as validator, 
          //otherwise create a validator from a closure to preserve fn for later use
          validate = (config[1]) ? fn : function(value) {
            return value.constructor === fn;
          };

      //see if arg value matches config
      if (validate(values[0])) {
        args.push(values.shift());
        continue;
      }
    }

    //add a default value if there is no value in the original args
    //or if the type didn't match
    args.push(config[2]);
  }

  return done();
}

2

मैं आपको ArgueJS का उपयोग करने की सलाह देता हूं

आप अपना फ़ंक्शन इस तरह से लिख सकते हैं:

function getData(){
  arguments = __({id: String, parameters: [Object], callback: [Function]})

  // and now access your arguments by arguments.id,
  //          arguments.parameters and arguments.callback
}

मैंने आपके उदाहरणों से माना कि आप अपने idपैरामीटर को एक स्ट्रिंग होना चाहते हैं , है ना? अब, getDataएक की आवश्यकता है String idऔर वैकल्पिक स्वीकार कर रहा है Object parametersऔर Function callback। आपके द्वारा पोस्ट किए गए सभी उपयोग मामले उम्मीद के मुताबिक काम करेंगे।



1

क्या आप कह रहे हैं कि आपके पास इस तरह के कॉल हो सकते हैं: गेटडाटा (आईडी, पैरामीटर); getData (आईडी, कॉलबैक)?

इस स्थिति में आप स्पष्ट रूप से स्थिति पर भरोसा नहीं कर सकते हैं और आपको टाइप का विश्लेषण करने पर निर्भर रहना होगा: getType () और यदि आवश्यक हो तो getTypeName ()

जाँच करें कि क्या प्रश्न में पैरामीटर एक सरणी या फ़ंक्शन है।


0

मुझे लगता है कि आप यहां टाइपोफ () का उपयोग करना चाहते हैं:

function f(id, parameters, callback) {
  console.log(typeof(parameters)+" "+typeof(callback));
}

f("hi", {"a":"boo"}, f); //prints "object function"
f("hi", f, {"a":"boo"}); //prints "function object"

0

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

function getData(id, opt){
    var data = voodooMagic(id, opt.parameters);
    if (opt.callback!=undefined)
      opt.callback.call(data);
    return data;         
}

getData(5, {parameters: "1,2,3", callback: 
    function(){for (i=0;i<=1;i--)alert("FAIL!");}
});

0

मुझे लगता है कि यह आत्म व्याख्यात्मक उदाहरण हो सकता है:

function clickOn(elem /*bubble, cancelable*/) {
    var bubble =     (arguments.length > 1)  ? arguments[1] : true;
    var cancelable = (arguments.length == 3) ? arguments[2] : true;

    var cle = document.createEvent("MouseEvent");
    cle.initEvent("click", bubble, cancelable);
    elem.dispatchEvent(cle);
}

-5

क्या आप फ़ंक्शन को ओवरराइड कर सकते हैं? क्या यह काम नहीं करेगा:

function doSomething(id){}
function doSomething(id,parameters){}
function doSomething(id,parameters,callback){}

8
नहीं, यह काम नहीं करेगा। आपको कोई त्रुटि नहीं मिलेगी लेकिन जावास्क्रिप्ट हमेशा आपके द्वारा परिभाषित नवीनतम फ़ंक्शन का उपयोग करेगा।
जद।

6
वाह। मुझे लगा कि तुम पागल हो। मैंने अभी इसका परीक्षण किया। तुम सही हो। मेरी दुनिया मेरे लिए बस थोड़ी सी बदल गई। मुझे लगता है कि मेरे पास यह सुनिश्चित करने के लिए कि मुझे उत्पादन में ऐसा कुछ भी नहीं है, आज देखने के लिए मेरे पास बहुत सारे जावास्क्रिप्ट हैं। टिप्पणी के लिए धन्यवाद। मैंने आपको +1 दिया।
जे। हेंड्रिक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.