4

I have a function like this:

let showNotification = function(a,b,c,d,e,f){
  console.log(a,b,c,d,e,f);
}

While calling this function, I know I need to follow order, something like this (if I dont want to pass param for c,d,e):

showNotification(1,2,,,,6);

But this forces me to make sure I pass all parameter and it should be in order..

I am looking for a better way to pass param in this case.

I know that I can create an object of param instead where instead of passing the values. something like this:

let showNotification = function(objectParam){
console.log(objectParam.a, objectParam.b, objectParam.c, objectParam.d, objectParam.e, objectParam.f)
}

then call it:

showNotification({a: 1, b: 2, e:6});

I can pass whole object but this is not what I am looking. I do not want to create object every time for this.

Thinking loud, if there is a way to pass the string values, without taking care of the order.

I see some dead SO posts regarding this, but no one has solution.

undefined
  • 3,464
  • 11
  • 48
  • 90
  • create a new method with required parameters. – Ramesh Rajendran Feb 23 '18 at 06:50
  • the thing is here all are optional, except the first param. – undefined Feb 23 '18 at 06:52
  • 2
    I can think of one funny way to do this, you can prepend or append(concat) tokens for respective parameter into your strings , e.g if you want to send parameter which represents parameter d , and string you want to pass is "myString", then you can decide format of your token like $&d&$ , so your parameter will look like "myString$&d&$" , then in your function you can simply scan for token and assign it respective variable by trimming/slicing the token out giving you actual string value. – BeeBee8 Feb 23 '18 at 07:05
  • Thanks a lot everyone for the response. I will wait for an hour more, and will accept the best answer (best way to do) – undefined Feb 23 '18 at 07:18

3 Answers3

1

TL;DR I know you didn't want to use an object, but modern JavaScript engines are really fast at creating and disposing of objects, and with parameter defaults and parameter destructuring, I think an options object is your best option. See "Notes on passing in an object (defaults, destructuring)" below for details.


You've covered two of the main options (I'm going to make some notes on the passing-in-an-object version below). A third option is to adopt the a variant of builder pattern, but it involves using an object too. You've said you don't want to do that, but haven't said why not. Note that modern JavaScript engines create and dispose of objects really, really fast if that's your concern.

Marker strings

A fourth option occurred to me when reading Bhushan Babar's append/prepend idea: Instead of doing that, you could use marker strings in the arguments list to indicate what the next argument is, e.g.:

showNotification("the required parameter", "a", value_for_a, "c", value_for_c);

On first glance, that doesn't involve creating an object, but on modern JavaScript engines, processing it will create an object that isn't otherwise created: arguments, the pseudo-array of passed-in arguments. Because that (or a rest parameter, which also creates an object) is the only reasonable way you could consume such a thing.

Variant on Builder

In this approach, the main function returns a builder object with setters for the various options, and then a final "Yep, we're ready" call that starts the process (where in the builder pattern that final call usually builds the final object). Using it would look something like this:

showNotification("the required param")
    .withA(value_for_a)
    .withC(value_for_c)
    .go();

Implementing this is complicated relative to other approaches, but not difficult.

Notes on passing in an object (defaults, destructuring)

If you do use an object (despite not wanting to), you can use default parameters and destructuring to make the object more convenient to work with:

let showNotification = function({a = 1, b = 2, c = 3, d = 4, e = 5, f = 6} = {/*default if no object at all*/a: "foo"}){
  console.log(a,b,c,d,e,f);
};

showNotification();
showNotification({});
showNotification({a:42});

In a comment you've said:

the thing is here all are optional, except the first param

That sounds like you probably want the first param and then an options object:

let showNotification = function(firstThing, {a = "default_a", b = "default_b"/*etc.*/} = {}) {
  console.log(firstThing, a, b);
};
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

@T,J. Crowder answer said better than this. In other way, you can do this by using spread Operators. As you said the thing is here all are optional, except the first param. So you should pass first parameter value. then you don't need to pass other value unless you want.But you should mention the position of parameter value as empty with , in an array. In my case you should create an object or array.

For example . If you have a dynamic array with values(whatever but position should be mandatory )and position [1,,,3]. then spread operator helps to merge that dynamic array with your function parameters.

let showNotification = function(a,b,c,d,e,f){
  console.log(a,b,c,d,e,f);
};

let parts = [2,3,,,6];//Think it is a dynamic array on run time or compile time
showNotification(1,...parts);

And here the @Felix Kling answers could help by using Named Parameters

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);
        };
    };
}());

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 

More examples:

Pass a value to a specific parameter without caring about the position of the parameter

Passing the argument name while calling function in javascript

JavaScript: Get Argument Value and NAME of Passed Variable

Ramesh Rajendran
  • 37,412
  • 45
  • 153
  • 234
  • Please also note that spread isn't an operator (and can't be). It's just syntax. – T.J. Crowder Feb 23 '18 at 07:15
  • @T.J.Crowder I have attached some link for this same concepts. May be that links helps to OP what he want. – Ramesh Rajendran Feb 23 '18 at 07:17
  • @T.J.Crowder I hope the spread operator is working for dynamic data passing. If he have an array with dynamic value with `,,` a parameter positions. then spread would be merge that. Is am correct? – Ramesh Rajendran Feb 23 '18 at 07:19
  • I get how spread helps here now (sorry for missing it), but can't say I think much of it; you still have the positional confusion. (Note that you don't have to use a variable: `showNotification(a, ...[2,3,,,6]);`.) – T.J. Crowder Feb 23 '18 at 07:20
  • @T.J.Crowder Absolutely. That's what i have mentioned your name in my answer on top. My idea is not about hard coded array/object. I am answered for dynamic `array` with the `object` position. – Ramesh Rajendran Feb 23 '18 at 07:27
1

Bhushan Babar hasn't posted his suggestion as a an answer, so I'll post it as a community wiki:

You can prepend or append(concat) tokens for respective parameter into your strings , e.g if you want to send parameter which represents parameter d , and string you want to pass is "myString", then you can decide format of your token like $&d&$ , so your parameter will look like "myString$&d&$"

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks @T.J. Crowder , I was not able to access this page, and all the notifications related to it were gone. Why did this happen? I was able to come back to this from my profile's 'all actions' tab – BeeBee8 Feb 27 '18 at 05:50
  • @BhushanBabar: I wouldn't know why you were having trouble with SO's website. – T.J. Crowder Feb 27 '18 at 07:30