views:

1368

answers:

7

I've always handled optional parameters in Javascript like this:

function myFunc(requiredArg, optionalArg){
  optionalArg = optionalArg || 'defaultValue';

  //do stuff
}

Is there a better way to do it?

Are there any cases where using || like that is going to fail?

+18  A: 

Your logic fails if optionalArg is passed, but evaluates as false - try this as an alternative

optionalArg = (typeof optionalArg == "undefined")?'defaultValue':optionalArg
Paul Dixon
That's exactly what I was looking for. Thanks!
Mark Biek
+3  A: 

http://www.openjs.com/articles/optional_function_arguments.php

slf
That's interesting. Passing arguments as an associative array seems like a good way to handle more than a couple arguments.
Mark Biek
That's exactly what I do in most cases. My functions with more than 1 argument expect an object literal.
Andrew Hedges
A: 

Try this basically if you call the method without the second parameter it will be null.

function myFunc(requiredArg, optionalArg){
 alert(requiredArg);
 if(optionalArg !=null) {
  alert(optionalArg);
 }
}

myFunc('foo'); //no need to specify the second arg

myFunc('foo','bar'); //second arg no longer null
Paul Whelan
+1  A: 

You can use some different schemes for that, I've always tested for arguments.length:

function myFunc(requiredArg, optionalArg){
  optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;

  ...

-- doing so, it can't possibly fail, but I don't know if your way has any chance of failing, just now I can't think up a scenario, where it actually would fail ...

Edit: And then Paul provided one failing scenario !-)

roenving
I am surprised no one has mentioned using the arguments array!
EvilSyn
+6  A: 

If you need to chuck a literal NULL in, then you could have some issues. Apart from that, no, I think you're probably on the right track.

The other method some people choose is taking an assoc array of variables iterating through the argument list. It looks a bit neater but I imagine it's a little (very little) bit more process/memory intensive.

function myFunction (argArray) {
    var defaults = {
     'arg1' : "value 1",
     'arg2' : "value 2",
     'arg3' : "value 3",
     'arg4' : "value 4"
    }

    for(var i in defaults) 
     if(typeof argArray[i] == "undefined") 
            argArray[index] = defaults[i];

    // ...
}
Oli
+4  A: 

Similar to Oli's answer, I use an argument Object and an Object which defines the default values. With a little bit of sugar...

/**
 * Updates an object's properties with other objects' properties.
 *
 * @param {Object} destination the object to be updated.
 * @param {Object} [source] all further arguments will have their properties
 *                          copied to the <code>destination</code> object in the
 *                          order given.
 *
 * @return the <code>destination</code> object.
 * @type Object
 */
function extendObject(destination)
{
    for (var i = 1, l = arguments.length; i < l; i++)
    {
        var source = arguments[i];
        for (var property in source)
        {
            if (source.hasOwnProperty(property))
            {
                destination[property] = source[property];
            }
        }
    }
    return destination;
}

...this can be made a bit nicer.

function Field(kwargs)
{
    kwargs = extendObject({
        required: true, widget: null, label: null, initial: null,
        helpText: null, errorMessages: null
    }, kwargs || {});
    this.required = kwargs.required;
    this.label = kwargs.label;
    this.initial = kwargs.initial;
    // ...and so on...
}

function CharField(kwargs)
{
    kwargs = extendObject({
        maxLength: null, minLength: null
    }, kwargs || {});
    this.maxLength = kwargs.maxLength;
    this.minLength = kwargs.minLength;
    Field.call(this, kwargs);
}

CharField.prototype = new Field();

What's nice about this method?

  • You can omit as many arguments as you like - if you only want to override the value of one argument, you can just provide that argument, instead of having to explicitly pass undefined when, say there are 5 arguments and you only want to customise the last one, as you would have to do with some of the other methods suggested.
  • When working with a constructor Function for an object which inherits from another, it's easy to accept any arguments which are required by the constructor of the Object you're inheriting from, as you don't have to name those arguments in your constructor signature, or even provide your own defaults (let the parent Object's constructor do that for you, as seen above when CharField calls Field's constructor).
  • Child objects in inheritance hierarchies can customise arguments for their parent constructor as they see fit, enforcing their own default values or ensuring that a certain value will always be used.
insin
A: 

Table: Distributor - dist_id

Table: menus - custid itemno

Table: load_sheet - id cat1 cat2

Table: categories - id

Relationships: Distributor.dist_id = menus.custid menus.itemno = load_sheet.id categories.id = load_sheet.cat1 OR categories.id = load_sheet.cat2

Goal: Logged in at a distributor (id: 353619). Display ONLY categories that have load_sheets that match whats in the distributors menu.

NOTE: The code below was originally designed to display ALL the categories (whether or not there were load_sheets under them).

Code:

$userid = isset($_REQUEST['id']) ? $_REQUEST['id'] : $_SESSION['userid']; $currDate = date("m-d-Y"); $catquery="SELECT * from categories ORDER BY id ASC"; $catresult=mysql_query($catquery); $catnum=mysql_num_rows($catresult);

if($catnum>0){

        echo '<form method="post" action="process_order.php?userid='. $userid. '">';
$rCnt=1;    
while($catobj=mysql_fetch_object($catresult))   {
    $catID=$catobj->id;
        echo '<table width="535" border="0" align="center" class="fmenu" cellpadding="0">';
        echo '<tr style="color: #6c7376;"><th align="left">&nbsp;<font size="3">'.$catobj->name.'</font></th></tr>';
        echo '<tr><td colspan="2" align="left" style="padding-left: 3px;"><i>'.str_replace("\r\n","<br />",$catobj->special).'</i></td></tr>';

    $lsquery="SELECT * FROM load_sheet INNER JOIN menus ON menus.custid = '$userid' AND load_sheet.autoID = menus.itemno WHERE (cat1='$catID' OR cat2='$catID')";

    if (isset($_REQUEST['id'])) {
    $lsquery .= "AND dateStart <= '$currDate' AND dateEnd >= '$currDate'";
    }

    $lsresult=mysql_query($lsquery);
    $lsnum=mysql_num_rows($lsresult);
        if($lsnum>0){

//----....etc

denim