Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I find the named parameters feature in C# quite useful in some cases.

calculateBMI(70, height: 175);

What if I want this in javascript?


What I don't want is -

myFunction({ param1 : 70, param2 : 175});

function myFunction(params){
    //check if params is an object
    //check if the parameters I need are non-null
    //blah-blah
}

That approach I've already used. Is there another way?

I'm okay using any library do this. (Or somebody can point me to one that already does)

share|improve this question
    
I dont think this is possible, but you can try to put some undefined's in empty places. Which is way bad. Use the object, its good. –  Vladislav Qulin Aug 3 '12 at 12:54
4  
Nope, JavaScript/EcmaScript don't support named parameters. Sorry. –  smilledge Aug 3 '12 at 12:54
    
I already know that. Thanks. I was looking for some way that involves tweaking what the existing Function in javascript can do. –  Robin Maben Aug 3 '12 at 12:57
1  
The existing Function in Javascript can't change Javascript's core syntax –  Gareth Aug 3 '12 at 13:04
    
@Gareth: Yes, but I can change the way it resolves its arguments, right? Or maybe put .apply to use? I do not mean strictly the C# way. Anyway that javascript can. (other than passing objects) –  Robin Maben Aug 3 '12 at 13:17
show 3 more comments

5 Answers

up vote 12 down vote accepted

There is a way to come close to what you want, but it is based on the output of Function.prototype.toString [ES5], which is implementation dependent to some degree, so it might not be cross-browser compatible.

The idea is to parse the parameter names from the string representation of the function so that you can associate the properties of an object with the corresponding parameter.

A function call could then look like

func(a, b, {someArg: ..., someOtherArg: ...});

where a and b are positional arguments and the last argument is an object with named arguments.

For example:

var parameterfy = (function() {
    var pattern = /function[^(]*\(([^)]*)\)/;

    return function(func) {
        // fails horribly for parameterless functions ;)
        var args = func.toString().match(pattern)[1].split(/,\s*/);

        return function() {
            var named_params = arguments[arguments.length - 1];
            if (typeof named_params === 'object') {
                var params = [].slice.call(arguments, 0, -1);
                if (params.length < args.length) {
                    for (var i = params.length, l = args.length; i < l; i++) {
                        params.push(named_params[args[i]]);
                    }
                    return func.apply(this, params);
                }
            }
            return func.apply(null, arguments);
        };
    };
}());

Which you would use as:

var foo = parameterfy(function(a, b, c) {
    console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);     
});

foo(1, 2, 3); // a is 1  | b is 2  | c is 3
foo(1, {b:2, c:3}); // a is 1  | b is 2  | c is 3
foo(1, {c:3}); // a is 1  | b is undefined  | c is 3
foo({a: 1, c:3}); // a is 1  | b is undefined  | c is 3 

DEMO

There are some drawbacks to this approach (you have been warned!):

  • If the last argument is an object, it is treated as a "named argument objects"
  • You will always get as many arguments as you defined in the function, but some of them might have the value undefined (that's different from having no value at all). That means you cannot use arguments.length to test how many arguments have been passed.

Instead of having a function creating the wrapper, you could also have a function which accepts a function and various values as arguments, such as

call(func, a, b, {posArg: ... });

or even extend Function.prototype so that you could do:

foo.execute(a, b, {posArg: ...});
share|improve this answer
    
Vow! Function.prototype.. I was hoping somebody would go in that direction.. –  Robin Maben Aug 3 '12 at 14:58
    
Yeah... here is an example for that: jsfiddle.net/9U328/1 ( though you should rather use Object.defineProperty and set enumerable to false). One should always be careful when extending native objects. The whole approach feels a bit hacky, so I would not expect it to work now and forever ;) –  Felix Kling Aug 3 '12 at 15:03
    
Noted. I will get down to putting this to use. Marking as answer! ...For now ;) –  Robin Maben Aug 3 '12 at 15:43
    
+1 for the term parameterification –  CSJ Dec 5 '13 at 21:08
add comment

No - the object approach is JavaScript's answer to this. There is no problem with this provided your function expects an object rather than separate params.

share|improve this answer
    
Explaining down vote : @Utkanos this more of a comment than an answer. –  Robin Maben Aug 3 '12 at 15:41
2  
@RobertMaben - The answer to the specific question asked is that there is no native way to collect declared vars or functions without knowing they live on a particular namespace. Just because the answer is short, it does not negate its suitability as an answer - wouldn't you agree? There are far shorter answers out there, along the lines of "no, no t possible". Short they may be, but they are also the answer to the question. –  Utkanos Aug 3 '12 at 16:31
add comment

bob.js can convert your regular function to the one that accepts named arguments, in one line:

func = bob.fn.namedArgFunction(func); 
share|improve this answer
    
Upvoted. Although it still looks exactly like the params object used in the question. –  Robin Maben Jul 25 '13 at 5:55
    
Well, difference is that first you can write a function without named parameters, just in a regular way. Therefore, you don't have to deal with the object inside the function. Next, call the bob.fn.namedArgFunction function as shown in my answer and that will return a function that can be called by passing an object to it. However, your function receives usual parameters. Yes, you still have to pass an object from the called code, but No, you don't have to deal with the single object parameter inside your function. This at least partially solves the problem. –  Tengiz Jul 25 '13 at 12:40
add comment

If you want to make it clear what each of the parameters are, rather than just calling

someFunction(70, 115);

why not do the following

var width = 70, height = 115;
someFunction(width, height);

sure, it's an extra line of code, but it wins on readability.

share|improve this answer
    
+1 for following the KISS principle, plus it also helps with debugging. However, I think each var should be on its own line, albeit with a slight performance hit (http://stackoverflow.com/questions/9672635/javascript-var-statement-and-perfor‌​mance). –  clairestreb Jun 19 at 14:55
add comment

Another way would be to use attributes of a suitable object, e.g. like so:

function plus(a,b) { return a+b; };

Plus = { a: function(x) { return { b: function(y) { return plus(x,y) }}}, 
         b: function(y) { return { a: function(x) { return plus(x,y) }}}};

sum = Plus.a(3).b(5);

Of course for this made up example it is somewhat meaningless. But in cases where the function looks like

do_something(some_connection_handle, some_context_parameter, some_value)

it might be more useful. It also could be combined with "parameterfy" idea to create such an object out of an existing function in a generic way. That is for each parameter it would create a member that can evaluate to a partial evaluated version of the function.

This idea is of course related to Schönfinkeling aka Currying.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.