How to put default (default) arguments in a Javascript function?

Asked

Viewed 7,191 times

31

In R this would be very simple:

funcao <- function(x=10) return(x)

If you call funcao() without arguments the result will be 10.

How to do the same in Javascript? And how to know if there are values default function without having to read the code?

  • I tried a way to check default values, but I ran into a problem: False-Positive, I implemented the following: check if the type was Undefined at the beginning and at the end did a check on the type again, if it had changed it is because it has default value, but when I passed a parameter it returned to me that there was no default value even existing.

  • I added a response with a method to make it easier to set default values. If someone is interested, and you want to contribute Function.prototype.Withdefaults.

  • I found another way to do it, simpler than what I did, but equally useful: cjwainwright / withDefaults.js

6 answers

37


The other answers are correct in general use, but if you want to be super strict and correct, you need to take the variable arguments under consideration. See this:

// Função identidade, com argumento padrão 10.
function f(x) {
    x = x || 10;
    // if (x == null) x = 10;
    // x = typeof x !== 'undefined' ? x : 10;
    return x;
}

f()           // => Retorna 10
f(3)          // => Retorna 3
f(null)       // => Retorna 10. Epa! Era para isso retornar null não?
f(undefined)  // => Retorna 10. Também!
f(0)          // => 10? Tá de brincadeira né?

Every function being invoked receives a special variable called arguments. It works as an array (has the property length and can be accessed numerically [0], [1], ...). For this identity function the most correct would be to do the following:

// Agora processando o arguments.
function f() {
    x = arguments.length > 0 ? arguments[0] : 10;
    return x;
}

f()     // => Retorna 10
f(3)    // => Retorna 3
f(null) // => Retorna null. Isso!

You can also add an error if more arguments are used:

if (arguments.length > 1) throw new Error("Too many arguments! Expected 1.");
  • 2

    Good, after that I even deleted my answer :)

  • 1

    Excellent, programming and learning :)

  • Although it is not very normal to ask something about an answer given here but, even for the answer to have an even greater scope, the definition of the standard values of each possible argument should be defined so, manually, one by one?

  • It is worth remembering that in the specification Ecmascript6 (Harmony) it is already possible to use default Parameters as follows: Function f(x=10){ Return x}. Some references: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/default_parameters http://wiki.ecmascript.org/doku.php?id=harmony:parameter_default_values http://globaldev.co.uk/2013/10/es6-part-4/#default-Parameters

  • The coolest thing is that there are several polyfills for Ecmascript6 (https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#ecmascript-6-Harmony), including support for default Parameters (https://github.com/termi/es6-transpiler#supported)

  • @Bruno, it is quite common to ask clarifications about answers in the comments, it helps to improve the answer. About doing everything in one line, there’s not much that helps. You can maybe write an auxiliary function or use something like args.js or the args-js or the argspecjs. Variants are there for all tastes.

Show 1 more comment

18

In javascript that current browsers (2015) use would have to have a if somehow within the function. But in the future, with browsers that support the new ES6 standard it is already possible.

What is possible today (2015):

Nowadays, with the Javascript version browsers use this is not possible. The solution to use is to check the value within the function, as mentioned in the question.

For example:

function b(a){
   if (typeof a == 'undefined') a = 1;
   return a;
}

Note: Firefox is already implementing some of ES6’s ideas but that’s not cross-browser compatible nowadays, hence unviable in production.

With ES6 - "Default Function Parameters"

When the new version of Javascript is implemented in browsers, as Firefox is already doing in this case, the solution will be (according to what the specifications of the Ecmascript) as it is in PHP (and that Firefox is already applying).

function b (a = 1) {
   return a;
}
console.log(b()); // dá: 1

15

Just as a curiosity (since the standard that is still valid is the version 5).

The Ecmascript 6 (alias Harmony) includes one proposal for syntax for parameters with default values. You can try it already the new syntax in Firefox. According to the Wikipedia the expected release date for the new standard is December 2014:

function multiply(a, b = 1) {
  return a*b;
}

multiply(5); // 5

UPDATE: Updating the response in November 2018. The Ecmascript 6, also known as ES2015 was released in June 2015 with syntax support above for default Function Parameters. This new syntax is supported in modern versions of major browsers, with notable exception of Internet Explorer (see compatibility table on MDN).

12

There is no way to do this in a practical way.

However, this answer does not please me, and knowing that javascript is such a dynamic language, I decided to use a little time to reflect, search and finally, putting together the pieces I created a method to allow indicating default values in an easy way.

How to use:

var funcao = (function(x) { return x; }).WithDefaults([10]);

Or a slightly more complex example, which is supported by WithDefaults:

var myFunc = (function (a) {
    return a + arguments[1];
}).WithDefaults([, "y"]);

Method code Function.prototype.WithDefaults

(function () {
    var setDefaults = function (a, d) {
        var l = Math.max(a.length, d.length);
        var p = [];
        for (var i = 0; i < l; i++)
            p[i] = i >= a.length || typeof a[i] == 'undefined' ? d[i] : a[i];
        return p;
    }

    var copyProperties = function (to, from, defs) {
        to.innerFunction = from;
        to.toString = function () {
            var strDefs = "";
            for (var i = 0; i < defs.length; i++)
                strDefs += (i > 0 ? ", " : "")
                    + (typeof defs[i] != 'undefined' ? JSON.stringify(defs[i]) : "");

            return "(" + from.toString() + ").WithDefaults(["
                + strDefs + "])";
        };
        for (var key in from)
            to[key] = from[key];
        return to;
    }

    var fnCreators = {
        0: function (f, d, sd, cp) {
            return cp(function () {
                return f.apply(this, sd(arguments, d));
            }, f, d);
        },
        1: function (f, d, sd, cp) {
            return cp(function (p1) {
                return f.apply(this, sd(arguments, d));
            }, f, d);
        },
        2: function (f, d, sd, cp) {
            return cp(function (p1, p2) {
                return f.apply(this, sd(arguments, d));
            }, f, d);
        },
        3: function (f, d, sd, cp) {
            return cp(function (p1, p2, p3) {
                return f.apply(this, sd(arguments, d));
            }, f, d);
        }
    };

    function getFnCreator(numParams) {
        if (typeof fnCreators[numParams] != 'undefined')
            return fnCreators[numParams];

        var paramNames = [];
        for (var i = 0; i < numParams; i++) {
            paramNames[i] = "p" + (i + 1);
        }

        fnCreators[numParams] = new Function("f", "d", "sd", "cp",
            "return cp(function(" + paramNames.join(",") + ") {\
                return f.apply(this, sd(arguments, d));\
            }, f, d);");

        return fnCreators[numParams];
    }

    Function.prototype.WithDefaults = function (defs) {
        var creator = getFnCreator(this.length);
        return creator(this, defs, setDefaults, copyProperties);
    }
})();

Example of use of the method WithDefaults in jsfiddle

  • Hey, great your code, the rest I found kind of a gambiarra that can, sounded more professional yours, should not have been pleased by the extension of the code, but this could be inserted in the jquery.js files of the site and act as a standard function.

  • I found this https://gist.github.com/cjwainwright/4678359 which is much simpler and short and simple, I don’t know if you did but it suits me very well, finally congratulations!

  • @user3715916 This gist is not mine... the code of that answer is mine. There’s a reason I did it this way: keep the length of the generated function. For a fn = function(x,y) => fn.length = 2. To fn2 = fn.WithDefaults([1,3]) => fn2.length = 2. I did this to keep as much original information as possible equal to the original function. Note also that up to the toString keeps returning the same thing.

  • I updated the jsfiddle to compare my solution with the gist you indicated.

10

There are some ways, but I prefer it this way:

function func(x){
    x = typeof x !== 'undefined' ? x : 10;
    return x;
}

Example

8

Thus:

function Retorno(x){
    if(x == 0)
        return x;

    x = x || 10; // Valor de x caso existir ou 10 que é o padrão
    return x;
}

I recommend reading of that answer of Miguel Angelo which better explains the functioning of ||(or) as a Javascript coalescence operator.

  • 4

    Testing with 0 in this case, the returned value is 15, which should not occur.

  • This is because Javascript 0 is treated as false, so I added an if if the value for zero returns x

Browser other questions tagged

You are not signed in. Login or sign up in order to post.