420

C#, for example, allows using named parameters like so:

calculateBMI(70, height: 175);

I find this quite useful. How can I get a similar effect in JavaScript?

I've tried doing things like

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
}

but it seems awkward. Is there a simpler way?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Robin Maben
  • 22,194
  • 16
  • 64
  • 99
  • 1
    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 03 '12 at 12:54
  • 37
    Nope, JavaScript/EcmaScript don't support named parameters. Sorry. – smilly92 Aug 03 '12 at 12:54
  • 1
    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 03 '12 at 12:57
  • 2
    The existing `Function` in Javascript can't change Javascript's core syntax – Gareth Aug 03 '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 03 '12 at 13:17
  • 1
    Coffeescript supports named parameters – mquandalle Jul 24 '13 at 20:57
  • @mquandalle: Any references? If credible, please post as an answer. – Robin Maben Jul 25 '13 at 05:54
  • @RobinMaben I found [this blog](http://jamie-wong.com/2011/11/28/name-your-arguments/). It shows how coffee has a syntax for implementing the object thing, but you can't use default values with it. – jpmc26 Aug 24 '13 at 06:28
  • I think this link maybe useful: http://www.javascriptkit.com/javatutors/namedfunction.shtml – A.Dara Nov 29 '15 at 10:37
  • 6
    I don't think Javascript supports this feature. I think the closest you can come to named parameters is (1) add a comment `calculateBMI(70, /*height:*/ 175);`, (2) provide an object `calculateBMI(70, {height: 175})`, or (3) use a constant `const height = 175; calculateBMI(70, height);`. – tim-montague Dec 23 '17 at 10:02

13 Answers13

422

ES2015 and later

In ES2015, parameter destructuring can be used to simulate named parameters. It would require the caller to pass an object, but you can avoid all of the checks inside the function if you also use default parameters:

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

function myFunction({param1, param2}={}){
  // ...function body...
}

// Or with defaults, 
function myFunc({
  name = 'Default user',
  age = 'N/A'
}={}) {
  // ...function body...
}

ES5

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: ...});
Nate Anderson
  • 18,334
  • 18
  • 100
  • 135
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Yeah... here is an example for that: http://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 03 '12 at 15:03
  • Noted. I will get down to putting this to use. Marking as answer! ...For now ;) – Robin Maben Aug 03 '12 at 15:43
  • 1
    *Very* minor nitpick:I don't think this approach will catch EcmaScript 6 [Arrow Functions](https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/). Not a huge concern currently, but might be worth mentioning in the caveats section of your answer. – NobodyMan Jun 09 '15 at 23:33
  • 3
    @NobodyMan: True. I wrote this answer before arrow functions were a thing. In ES6, I would actually resort to parameter destructuring. – Felix Kling Jun 09 '15 at 23:38
  • Here is syntax with the default parameters: `function myFunction({param1 = 1, param2 = 2} = {}){` – Darek Nędza Mar 21 '17 at 00:19
  • This would be better with a demo of parameter destructuring. I'd add it, but I'm having trouble understanding it! – mikemaccana Oct 12 '18 at 11:28
  • "That means you cannot use arguments.length to test how many arguments have been passed." -- you can easily filter out the `undefined` values. – Dmitri Zaitsev Aug 23 '19 at 03:04
  • @DmitriZaitsev: `undefined` could be passed explicitly, but maybe that's irrelevant. – Felix Kling Aug 23 '19 at 11:15
  • I would see it as a bad fragile design if the function indeed needs to distinguish between no value and explicit `undefined`. But if you really have to, you can still see all explicitly passed `undefined` with `Object.entries` from your object argument. – Dmitri Zaitsev Aug 25 '19 at 01:45
  • 1
    On the issue of `undefined` vs "no value", it can be added that this is exactly how JS functions' default values are working -- treating `undefined` as a missing value. – Dmitri Zaitsev Aug 27 '19 at 02:06
  • Explicit `undefined` is an antipattern in JavaScript - use `null` for explicit nothing – ThaJay Jan 23 '20 at 10:32
  • I don't understand the meaning of this drawback: *'If the last argument is an object, it is treated as a "named argument objects"'* - can someone explain? – Yarin Mar 07 '21 at 00:02
  • 1
    @Yarin: This "solution" assumes that if an object is passed as the last argument to the function call then the object contains values for "named" parameters. But that assumption doesn't work if the function naturally expects to be passed an object as argument. E.g. consider `function deleteUser(user) { ... }`. `deleteUser({name: ...})` doesn't work because the object is interpreted as "named parameter object". You'd have to write `deleteUser({user: {name: ...}})`. – Felix Kling Mar 07 '21 at 10:01
  • I have a function func(a,b,c,d,e, f=false) which is used many places I call the function as func(a,b, {f: true}), but f is still coming as false.. Can someone please help – sk215 Mar 10 '23 at 02:31
  • Could you please elaborate the **ES2015 and later** version at the top. `function myFunction({param1, param2}={}) { ... }` looks to me like 1. assigning an empty array or object to an array or object with two members (which usually doesn't work LHS-wise), 2. supplying `myFunction` with the result of this not working assignment as one single argument. – Gerold Broser Jun 10 '23 at 22:19
97

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.

Mitya
  • 33,629
  • 9
  • 60
  • 107
  • 4
    Nowadays there is es6 though: http://www.2ality.com/2011/11/keyword-parameters.html – slacktracer Jan 12 '16 at 18:32
  • 3
    This is definitely a fair answer — 'named parameters' is a language feature. The object approach is the next best thing in the absence of such a feature. – fatuhoku Jan 19 '16 at 18:07
  • When using the object approach, if we have to rename an arg name, then refactoring can become an issue. We will need to go to each invocation and change the arg object; There is a fair chance of missing an invocation and running in to run-time issue. – NSaran Sep 22 '22 at 18:14
48

Lots of people say to just use the "Pass an object" trick so that you have named parameters.

/**
 * My Function
 *
 * @param {Object} arg1 Named arguments
 */
function myFunc(arg1) { }

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

And that works great, except... when it comes to most IDEs out there, a lot of us developers rely on type / argument hints within our IDE. I personally use PhpStorm (along with other JetBrains IDEs, like PyCharm for Python and AppCode for Objective-C).

And the biggest problem with using the "Pass an object" trick is that when you are calling the function, the IDE gives you a single type hint and that's it... How are we supposed to know what parameters and types should go into the arg1 object?

I have no idea what parameters should go in arg1

So... the "Pass an object" trick doesn't work for me... It actually causes more headaches with having to look at each function's docblock before I know what parameters the function expects.... Sure, it's great for when you are maintaining existing code, but it's horrible for writing new code.

Well, this is the technique I use... Now, there may be some issues with it, and some developers may tell me I'm doing it wrong, and I have an open mind when it comes to these things... I am always willing to look at better ways of accomplishing a task... So, if there is an issue with this technique, then comments are welcome.

/**
 * My Function
 *
 * @param {string} arg1 Argument 1
 * @param {string} arg2 Argument 2
 */
function myFunc(arg1, arg2) { }

var arg1, arg2;
myFunc(arg1='Param1', arg2='Param2');

This way, I have the best of both worlds. New code is easy to write as my IDE gives me all the proper argument hints. And, while maintaining code later on, I can see at a glance, not only the value passed to the function, but also the name of the argument. The only overhead I see is declaring your argument names as local variables to keep from polluting the global namespace. Sure, it's a bit of extra typing, but it's trivial compared to the time it takes to look up docblocks while writing new code or maintaining existing code.

Now, I have all the parameters and types when creating new code

Update - 2022

JavaScript now has the ability to have something close to named parameters using object destructuring available in ES6. Most newer browsers can use this feature See browser support

This is how it works:


// Define your function like this
function myFunc({arg1, arg2, arg3}) {
    // Function body
}

// Call your function like this
myFunc({arg1: "value1", arg2: "value2", arg3: "value3"})

// You can also have default values for arguments
function myFunc2({firstName, lastName, age = 21}) {
    // Function body
}

// And you can call it with or without an "age" argument
myFunc({firstName: "John", lastName: "Doe"}) // Age will be 21
myFunc({firstName: "Jane", lastName: "Doe", age: 22})

The best part is that most IDE's now support this syntax and you get good argument hint support

TypeScript

For those of you using TypeScript, you can do the same thing using this syntax

function myFunc(
    {firstName, lastName, age = 21}:
    {firstName: string, lastName: string, age?: number}
) {
    // Function body
}

OR, using an interface

interface Params {
    firstName: string
    lastName: string
    age?: number
}

function myFunc({firstName, lastName, age = 21}: Params) {
    // Function body
}
Ray Perea
  • 5,640
  • 1
  • 35
  • 38
  • 3
    The only thing with this technique is the fact that you can't change the order of the parameters... I am personally fine with that though. – Ray Perea Jul 10 '14 at 20:11
  • 29
    Seems like this is just asking for trouble when some future maintainer comes along and thinks they can change argument order (but obviously can't). – nobody Jul 10 '14 at 20:19
  • 1
    @AndrewMedico I agree... it does look like you can just change the argument order like in Python. The only thing I can say about that is they'll find out real quick when changing the argument order breaks the program. – Ray Perea Jul 10 '14 at 20:27
  • 12
    I'd argue that `myFunc(/*arg1*/ 'Param1', /*arg2*/ 'Param2');` is better than `myFunc(arg1='Param1', arg2='Param2');`, because that has no chance of tricking the reader than any actual named arguments are happening – Eric Sep 21 '16 at 09:24
  • @Eric. I hadn't thought of using comments within the function call.... That's great.... The only thing with this method is that with comments, I don't have auto complete so I'd have to type out each argument name manually... But, then again, I'd have to do that anyway when I define the vars in the first place..... Thanks for your insight. – Ray Perea Sep 21 '16 at 16:53
  • The naming in the latter code should be the other way round, shouldn't it? [`arg1`, `arg2` are (_formal_) _parameters_ of the function. `'Param1'`, `'Param2'` are _actual parameters_ / _arguments_](https://en.wikipedia.org/wiki/Parameter_(computer_programming)#Parameters_and_arguments) to the function. – Gerold Broser Apr 14 '17 at 11:03
  • scala also has named params – CommonSenseCode Jul 13 '17 at 08:21
  • @GeroldBroser `'Param1'` and `'Param2'` are values not placeholders, like `arg1` and `arg2`. – GoldBishop Nov 14 '17 at 18:22
  • @GoldBishop Yes, I'm aware of that and that's my point, too. Values → arguments, placeholders → parameters. – Gerold Broser Nov 14 '17 at 20:02
  • @GeroldBroser Values are not necessarily arguments but arguments can be placeholders or parameters. Think of it like Command-Line tools, they refer to arguments (in documentation) but they are ultimately placeholders and/or parameters. The value is not relevant to the argument but the argument is relevant to the purpose of its use (placeholder/parameter). – GoldBishop Nov 15 '17 at 12:36
  • @GoldBishop We are talking about functions here, right? What are arguments to a function other than the values passed to it? Such, the value is relevant, since it is the argument to a function. A function itself is a placeholder: for its return value. I linked a reference. Can you do the same for your POV? – Gerold Broser Nov 15 '17 at 20:59
  • @GeroldBroser Arguments are pointers to the value, by most compilers. Don't confuse the lower-level operations with higher-level explanations. All variables (parameters) are placeholders for a value, whether byref or byval. But the context of the question was how to explicitly refer to specific parameters, especially in an out of order approach; very similar to what you can do in most OOP languages. I understand JS is TypeScript and has VERY LOOSE rules. – GoldBishop Nov 16 '17 at 18:32
  • @GoldBishop I'm not confusing low-level with high-level. I was talking about the latter so far. You introduced compilers right now. If a parameter is a constant, there's no pointer at all, its value is inserted in-line as argument to the function, by most compilers. Apart from that compilers do not know much about arguments/values passed to a function. They are pushed to/popped from a stack, by most runtime systems. Byref or byval is a detail that's not relevant in the high-level respect I was talking about. Do you have a reference for your POV? – Gerold Broser Nov 17 '17 at 00:30
  • Python's lambdas also carry counterintuitive surprises like bind at the execution time https://realpython.com/python-lambda/ – Dmitri Zaitsev Aug 23 '19 at 03:21
  • 10
    The pattern proposed has nothing to do with named arguments, the order still matters, the names don't need to stay in sync with the actual parameters, namespace is polluted with unnecessary variables and relationships are implied that aren't there. – Dmitri Zaitsev Aug 23 '19 at 03:30
  • 4
    Sorry, but this is not worth calling a "technique", this does not answer the question as it does *not* give you named paramters, it introduces unnecessary variables, it is totally misleading if you just think about what `myFunc(arg2='Param2', arg1='Param1');` or `myFunc(arg2='Param2');` would do. It's a total anti-pattern and just a horrible answer. Please remove! – Elmar Zander Feb 06 '21 at 23:33
  • in visual studio code, the parametres do actually show correctly if you do eg `somefunction({x, y})` – Hugh Perkins Nov 14 '21 at 17:54
  • 1
    @HughPerkins That’s awesome. It’s been years since I answered this question. And back then, the options were very limited. So the fact that some IDEs now support that is great. – Ray Perea Nov 15 '21 at 19:08
27

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

someFunction(70, 115);

do the following:

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

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dav_i
  • 27,509
  • 17
  • 104
  • 136
  • 6
    +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-performance](http://stackoverflow.com/questions/9672635/javascript-var-statement-and-performance)). – clairestreb Jun 19 '14 at 14:55
  • 53
    It's not only about the extra line of code, it's also about the order of the arguments and making them optional. So you could write this with named parameters: `someFunction(height: 115);`, but if you write `someFunction(height);` you are actually setting the width. – Francisco Presencia Apr 30 '15 at 06:51
  • 1
    In that case, CoffeeScript supports named arguments. It will let you write just `someFunction(width = 70, height = 115);`. The variables are declared at the top of the current scope in the JavaScript code which is generated. – Audun Olsen Jan 14 '19 at 09:00
7

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.

Udo Klein
  • 6,784
  • 1
  • 36
  • 61
  • 1
    This is a neat idea, and becomes even better if you combine it with the argument introspection tricks. Unfortunately, it falls short of working with optional arguments – Eric Sep 21 '16 at 09:26
3

Calling function f with named parameters passed as the object

o = {height: 1, width: 5, ...}

is basically calling its composition f(...g(o)) where I am using the spread syntax and g is a "binding" map connecting the object values with their parameter positions.

The binding map is precisely the missing ingredient, that can be represented by the array of its keys:

// map 'height' to the first and 'width' to the second param
binding = ['height', 'width']

// take binding and arg object and return aray of args
withNamed = (bnd, o) => bnd.map(param => o[param])

// call f with named args via binding
f(...withNamed(binding, {hight: 1, width: 5}))

Note the three decoupled ingredients: the function, the object with named arguments and the binding. This decoupling allows for a lot of flexibility to use this construct, where the binding can be arbitrarily customized in function's definition and arbitrarily extended at the function call time.

For instance, you may want to abbreviate height and width as h and w inside your function's definition, to make it shorter and cleaner, while you still want to call it with full names for clarity:

// use short params
f = (h, w) => ...

// modify f to be called with named args
ff = o => f(...withNamed(['height', 'width'], o))

// now call with real more descriptive names
ff({height: 1, width: 5})

This flexibility is also more useful for functional programming, where functions can be arbitrarily transformed with their original param names getting lost.

Dmitri Zaitsev
  • 13,548
  • 11
  • 76
  • 110
2

There is another way. If you're passing an object by reference, that object's properties will appear in the function's local scope. I know this works for Safari (haven't checked other browsers) and I don't know if this feature has a name, but the below example illustrates its use.

Although in practice I don't think that this offers any functional value beyond the technique you're already using, it's a little cleaner semantically. And it still requires passing a object reference or an object literal.

function sum({ a:a, b:b}) {
    console.log(a+'+'+b);
    if(a==undefined) a=0;
    if(b==undefined) b=0;
    return (a+b);
}

// will work (returns 9 and 3 respectively)
console.log(sum({a:4,b:5}));
console.log(sum({a:3}));

// will not work (returns 0)
console.log(sum(4,5));
console.log(sum(4));
1

NB. My answer of 2016 is not correct and misleading as mentioned in comments.

Trying Node-6.4.0 ( process.versions.v8 = '5.0.71.60') and Node Chakracore-v7.0.0-pre8 and then Chrome-52 (V8=5.2.361.49), I've noticed that named parameters are almost implemented, but that order has still precedence. I can't find what the ECMA standard says.

>function f(a=1, b=2){ console.log(`a=${a} + b=${b} = ${a+b}`) }

> f()
a=1 + b=2 = 3
> f(a=5)
a=5 + b=2 = 7
> f(a=7, b=10)
a=7 + b=10 = 17

But order is required!! Is it the standard behaviour?

> f(b=10)
a=10 + b=2 = 12
jgran
  • 1,111
  • 2
  • 11
  • 21
  • 14
    That's not doing what you think. The result of the `b=10` expression is `10`, and that's what is passed to the function. `f(bla=10)` would also work (it assigns 10 to the variable `bla` and passes the value to the function afterwards). – Matthias Kestenholz Nov 17 '16 at 13:24
  • 4
    This is also creating `a` and `b` variables in the global scope as a side-effect. – Gershom Maes Dec 11 '18 at 01:44
  • Re *"My answer of 2016"*: Do you mean this answer? In that case, better delete it (or fix it). – Peter Mortensen Oct 19 '22 at 02:27
  • Well, I thought the two upvoted comment helped me to understand better named parameters in ES-6+ and could still be useful for people new to JS or coming from other languages which behave differently. I might be wrong. – jgran Oct 19 '22 at 07:39
1

Coming from Python this bugged me. I wrote a simple wrapper/Proxy for node that will accept both positional and keyword objects.

https://github.com/vinces1979/node-def/blob/master/README.md

Tobias
  • 2,481
  • 3
  • 26
  • 38
Vince Spicer
  • 4,325
  • 3
  • 21
  • 11
  • If I understand correctly, your solution requires to distinguish positional and named params in the function's definition, which means I don't have the freedom to make this choice at the call time. – Dmitri Zaitsev Aug 25 '19 at 01:52
  • @DmitriZaitsev: In the Python community (with keyword arguments being an everyday feature), we consider it a very good idea to _be able_ to force users to specify optional arguments by keyword; this helps to avoid errors. – Tobias Dec 17 '19 at 16:50
  • @Tobias Forcing users doing so in JS is a solved problem: `f(x, opt)`, where `opt` is an object. Whether it helps to avoid or to create errors (such as caused by misspelling and the pain to remember keyword names) remains a question. – Dmitri Zaitsev Dec 18 '19 at 04:53
  • @DmitriZaitsev: In Python this strictly _avoids_ errors, because (of course) keyword arguments are a core language feature there. For keyword-_only_ arguments, Python 3 has [special syntax](https://www.python.org/dev/peps/pep-3102/) (while in Python 2 you would pop the keys from the `kwargs` [dict](https://docs.python.org/2/library/stdtypes.html#mapping-types-dict) one by one and finally raise a `TypeError` if unknown keys are left). Your `f(x, opt)` solution _allows_ the `f` function to do something like in Python 2, but you would need to handle all default values yourself. – Tobias Jan 07 '20 at 11:09
  • @Tobias Is this proposal relevant for JS? It seems to describe how `f(x, opt)` is already working, while I don't see how this helps to answer the question, where e.g. you want to do both `request(url)` and `request({url: url})` that wouldn't be possible by making `url` a keyword-only parameter. – Dmitri Zaitsev Jan 09 '20 at 05:25
  • I simply anwered to your remark, "this is a solved problem in Javascript". No, it isn't, and probably never will be, because of different language concepts. In JS, you can only force users to provide an options object; in Python, the function signature can tell you about the exact name of each keyword-only option. – Tobias Jan 09 '20 at 10:08
1

This is admittedly pseudocode, but I believe it'll work (I know it works in TypeScript; I'm adopting it for JavaScript).

// Target Function
const myFunc = (a=1,b=2,c=3) => {a+b+c}

// Goal usage:
myFunc(a=5, b=6) // 14
myFunc(c=0) // 3

// Set your defaults
const myFuncDefaults = {a:1, b:2, c:3};

// Override them with passed parameters
const myFuncParams = (params) => { return Object.assign(myFuncDefaults, params)}


// Use the overloaded dict as the input
const myFunc2 = (params) => {
  let {a, b, c} = myFuncParams(params);
  return myFunc(a, b, c)
}

// Usage:
myFunc({a:5, b:6}) // 14
myFunc({c:0}) // 3

// Written more succinctly:
const myFunc = (params) => {
  let {a,b,c} = Object.assign({a:1, b:2, c:3}, params)
  return a + b + c
}

For what it's worth, TypeScript makes this kind of nice with hinting:

interface IParams {
  a: number;
  b: number;
  c: number;
}

const myFunc = (params: Partial<IParams>): number => {
  const default: IParams = {a:1, b:2, c:3};
  let {a, b, c} = Object.assign(default, params)
  return a + b + c
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Schalton
  • 2,867
  • 2
  • 32
  • 44
1

I had a similar problem, but for an Object. This is an oversimplification of the problem and solution:

Suppose I have a Car object:

function Car(miles = 0, images = [], axles = 2){
 this.miles = miles
 this.images = images
 this.axles = axles
 return this
}

But suppose when I create a new car, I don't have the images yet:

let car = Car(miles = 1000, axles = 3)  

Creating car like this, js does not read the param name and just assigns the values as they come in:

Car{ miles:1000, images:3, axles:2 }  // images should be [], and axles 3!

My solution is to create the object first, then assign the values:

let car = new Car()
car.miles = 1000
car.axles = 3

And now the params are assigned to the correct members:

Car{ miles:1000, images=[] ,axles=3 }

And this solves the IDE-not-knowing-param-names problem when you convert the parameters to an object.

So for your specific solution, you could do this (although it seems like overkill given the simplicity of our examples):

let mf = new MyFunction()
mf.param1 =  70
mf.param2 = 175

function MyFunction(param1=0,param2=0){
  this.param1 = param1
  this.param2 = param2
}
Travis Heeter
  • 13,002
  • 13
  • 87
  • 129
0

Yes, well, kind of. I've found two solutions. I'll explain just one.

In this solution, we give up positional arguments, though.

We can use an object (almost identical to a dict in Python) to pass the arguments.

In this example, I'm using the function to generate the name of a image file:

// First we define our function with just ONE argument
function name_of_img(img_desc){

  // With this step, any undefined value will be assigned a value
  if(img_desc.size == undefined) {img_desc.size = "400x500"}
  if(img_desc.format == undefined) {img_desc.format = ".png"}

  console.log(img_desc.size + img_desc.format)
}

// Notice inside our function we're passing a dict/object

name_of_img({size: "200x250", format : ".jpg"})
// In Python name_of_img(size="200x250" , format="jpg")
// returns "200x250.jpg"

name_of_img({size: "1200x950"})
// In Python name_of_img(size="1200x950")
// returns "1200x950.png"

We can modify this example, so we can use positional arguments too, we can also modify it so non valid arguments can be passed, I think I will make a GitHub repository about this.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
-3

Contrary to what is commonly believed, named parameters can be implemented in standard, old-school JavaScript (for boolean parameters only) by means of a simple, neat coding convention, as shown below.

function f(p1=true, p2=false) {
    ...
}

f(!!"p1"==false, !!"p2"==true); // call f(p1=false, p2=true)

Caveats:

  • Ordering of arguments must be preserved - but the pattern is still useful, since it makes it obvious which actual argument is meant for which formal parameter without having to grep for the function signature or use an IDE.

  • This only works for booleans. However, I'm sure a similar pattern could be developed for other types using JavaScript's unique type coercion semantics.

user234461
  • 1,133
  • 12
  • 29
  • 1
    You are still referring by position, not by name here. – Dmitri Zaitsev Aug 23 '19 at 03:09
  • 1
    @DmitriZaitsev yes, I even said so above. However, the purpose of named arguments is to make it clear to the reader what each argument means; it's a form of documentation. My solution enables documentation to be embedded within the function call without resorting to comments, which look untidy. – user234461 Aug 27 '19 at 09:19
  • 3
    This solves a different problem. The question was about passing `height` by name irrespective of the param order. – Dmitri Zaitsev Aug 27 '19 at 09:53
  • @DmitriZaitsev actually, the question didn't say anything about parameter order, or why OP wanted to use named params. – user234461 Aug 27 '19 at 12:53
  • 1
    It does by referring to C# where passing params by name in any order is the key. – Dmitri Zaitsev Aug 28 '19 at 00:20
  • @DmitriZaitsev This is a class example of the XY problem (in more ways than one). OP is requesting named parameters because they want their code to be readable. A side effect of their implied solution is that order no longer matters. You're fixating on a minor, weird piece of syntactic sugar while missing the main point. – user234461 Aug 30 '19 at 14:08
  • If you consult any introduction to named arguments, independence of position and optionality are named prominently as the main features. The documenting part is unrelated because it is achievable with comments. Your statement "they can be implemented in standard JS" is simply not true. – Dmitri Zaitsev Sep 02 '19 at 05:19
  • @DmitriZaitsev But in my method the arguments ARE OPTIONAL. (Provided they are defined to be in a sensible order, of course.) Comments are bad. Comments are frequently wrong. Naming variables (and string-based "pseudo-variables") sensibly obviates the need for any comments whatsoever. – user234461 Sep 02 '19 at 10:26
  • "But in my method the arguments ARE OPTIONAL" -- they are not: you cannot drop an argument in the middle. – Dmitri Zaitsev Sep 04 '19 at 17:48
  • @DmitriZaitsev You can if you drop all following arguments, as implied by the parenthesised comment to that effect. – user234461 Sep 05 '19 at 14:20
  • you cannot drop an argument **in the middle** – Dmitri Zaitsev Sep 06 '19 at 15:37
  • 1
    @DmitriZaitsev never said you could. – user234461 Sep 16 '19 at 09:48