2

Let say I have a function that has 50 arguments, and I need to modify the values of each named-variable that was created inside the function's signature.

Instead of 50 arguments, he's an example with just 4:

// Each of these strings are padded with intentional and unnecessary whitespace:
let show = "  show ";
let me = " me  ";
let the = " the ";
let bunny = "  bunny   ";

function showMeTheBunny(show, me, the, bunny)
{
 // I want to trim each argument, without having to do this:
 show = show.trim();
 me = me.trim();
 the = the.trim();
 bunny = bunny.trim();
 // The above lines, within this function,
 // are the ones I want to replace with a loop (if possible)

 return `${show} ${me} ${the} ${bunny}: `; 
}
console.log(showMeTheBunny(show, me, the, bunny)); // output: "show me the bunny: "

The arguments object can access all the arguments passed into a function, but it doesn't seem to offer a way to change the values of the named-variables themselves.

Is it possible to run all the named-variables (named within a function signature) through a function that modifies each of them before consuming those modified arguments later (using the same variable names)?

Lonnie Best
  • 9,936
  • 10
  • 57
  • 97
  • 4
    *"Let say I have function that has 50 arguments..."* Youch! – T.J. Crowder Nov 05 '19 at 08:25
  • My point is, when you have a lot of arguments that need to be modified the same way, the normal syntax for doing so is not ideal. I'm hoping there's a more elegant way I've overlook, in my study of the language. – Lonnie Best Nov 05 '19 at 08:28
  • 1
    I don't get what you mean by `named-variables`, can you show a `unnamed-variable`? – apple apple Nov 05 '19 at 08:28
  • @appleapple Perhaps my terminology is wrong. Maybe `variable` alone is enough. My point is, I want to use the variables that were named in the function signature after modifying all of them with a loop. – Lonnie Best Nov 05 '19 at 08:33
  • @appleapple TJ says they're called `formal parameters`. I wasn't sure, I had to make up my on terms from lack of knowing the official ones. – Lonnie Best Nov 05 '19 at 08:36
  • @LonnieBest it's fine, I just don't get why you add the `named` while there is no `unnamed` one :/ it makes me think you have something special to indicate. – apple apple Nov 05 '19 at 08:37
  • just out of curiosity, could you post the signature of the real function with 50 arguments? – georg Nov 05 '19 at 08:39
  • @georg : I can't post that, but I'll tell you this. The real function's arguments fuel a dynamically created SQL statement, where each argument's value has to be prepped before going into a template literal. The purpose is for preventing sql injection attacks and I'm just looking for a more elegant way to prep each argument. – Lonnie Best Nov 05 '19 at 08:43
  • 2
    @LonnieBest: I see. Commonly such functions have a signature `sqlExecute(statement, args)`, where `args` is an array if you use positional placeholders, or an object if you use named ones. – georg Nov 05 '19 at 08:48
  • @georg Yeah, I know, but it is very cool when you can keep the actual names instead of `${ary[0]}` inside the template literal. Also `${obj.name}` is more verbose than just `${name}`; – Lonnie Best Nov 05 '19 at 08:51
  • 2
    @LonnieBest - True. You can get around that by using destructuring. For instance, assuming you accept an object: `for (const [name, value] of Object.entries(args)) { args[name] = value.trim(); }` followed by `const {show, me, the, bunny} = args;`. It has the advantage that you don't have to worry about the order. – T.J. Crowder Nov 05 '19 at 08:54
  • 1
    @LonnieBest: yes, but who says you have to use a template? Pass a normal string with your own placeholders, like `WHERE {whatever} > 0` and replace them on the fly. Templates are a wrong tool here. – georg Nov 05 '19 at 08:54
  • 1
    See https://stackoverflow.com/questions/22607806/defer-execution-for-es6-template-literals for possible options. – georg Nov 05 '19 at 08:56
  • @georg : I acknowledge your point. – Lonnie Best Nov 05 '19 at 09:25
  • 1
    glad to hear that, @LonnieBest – georg Nov 05 '19 at 09:37

4 Answers4

3

You mean this?

Convert the iterative arguments to an array and map it

Array.from(arguments) or [...arguments] will work here

This does not actually modify the actual argument array as pointed out by TJ

// Each of these strings are padded with intentional and unnecessary whitespace:
let show = "  show ";
let me = " me  ";
let the = " the ";
let bunny = "  bunny   ";

function showMeTheBunny(show, me, the, bunny) {
  return Array.from(arguments).map(el => el.trim()).join(" ")+": ";
}
console.log(showMeTheBunny(show, me, the, bunny)); // output: "show me the bunny"
mplungjan
  • 169,008
  • 28
  • 173
  • 236
3

You've said you want to modify the values of the "named variables" so I assume you mean the formal parameters (show, me, etc.)

The arguments object can access all the arguments passed into a function, but it doesn't seem to offer a way to change the values of the named-variables themselves.

It does, but only in loose mode, not strict mode:

function showMeTheBunny(show, me, the, bunny)
{
    for (let n = 0; n < arguments.length; ++n)
    {
        arguments[n] = arguments[n].trim();
    }
    return `${show} ${me} ${the} ${bunny}: `;
}

In that, arguments[0] = arguments[0].trim() updates the value of the show formal parameter, arguments[1] = arguments[1].trim() updates me, etc. But only in loose mode. In strict mode, only arguments[x] would be updated, not the formal parameter; the link back to it is removed. (It's worth noting that strict mode is the default in modules and class constructs.)

Live Example:

// Each of these strings are padded with intentional and unnecessary whitespace:
let show = "  show ";
let me = " me  ";
let the = " the ";
let bunny = "  bunny   ";

function showMeTheBunny(show, me, the, bunny)
{
    for (let n = 0; n < arguments.length; ++n)
    {
        arguments[n] = arguments[n].trim();
    }
 return `${show} ${me} ${the} ${bunny}: `;
}
console.log(showMeTheBunny(show, me, the, bunny)); // output: "show me the bunny"

There are other ways, but they wouldn't modify the values of the formal parameters. For instance, you could use a rest parameter:

function showMeTheBunny(...rest)
{
    rest = rest.map(entry => entry.trim());
    const [show, me, the, bunny] = rest;
    return `${show} ${me} ${the} ${bunny}: `;
}

Live Example:

"use strict";
// Each of these strings are padded with intentional and unnecessary whitespace:
let show = "  show ";
let me = " me  ";
let the = " the ";
let bunny = "  bunny   ";

function showMeTheBunny(...rest)
{
    rest = rest.map(entry => entry.trim());
    const [show, me, the, bunny] = rest;
 return `${show} ${me} ${the} ${bunny}: `;
}
console.log(showMeTheBunny(show, me, the, bunny)); // output: "show me the bunny"

That works in strict mode.

Another option is to accept an object with properties for the parameters, then (again) use destructuring to get individual variables:

function showMeTheBunny(args)
{
    for (const [name, value] of Object.entries(args)) {
        args[name] = value.trim();
    }
    const {show, me, the, bunny} = args;
    return `${show} ${me} ${the} ${bunny}: `;
}

Live Example:

"use strict";
// Each of these strings are padded with intentional and unnecessary whitespace:
let show = "  show ";
let me = " me  ";
let the = " the ";
let bunny = "  bunny   ";

function showMeTheBunny(args)
{
    for (const [name, value] of Object.entries(args)) {
        args[name] = value.trim();
    }
    const {show, me, the, bunny} = args;
 return `${show} ${me} ${the} ${bunny}: `;
}
console.log(showMeTheBunny({show, me, the, bunny})); // output: "show me the bunny"

That also works in strict mode.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
3

The properties of an arguments object are actually setters. If you reassign a property on the argument, the corresponding variable name will change as well. So you can iterate through the arguments and reassign them:

// Each of these strings are padded with intentional and unnecessary whitespace:
let show = "  show ";
let me = " me  ";
let the = " the ";
let bunny = "  bunny   ";

function showMeTheBunny(show, me, the, bunny)
{
  [...arguments].forEach((arg, i) => {
    arguments[i] = arg.trim();
  });
 return `${show} ${me} ${the} bunny`; 
}
console.log(showMeTheBunny(show, me, the, bunny)); // output: "show me the bunny"

But this is really really really weird. Pretty much nothing else in Javascript exhibits this extremely un-intuitive behavior. Consider changing your function around instead.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    Worth noting that `arguments` doesn't behave this way in strict mode. The link back to the formal parameters is removed. – T.J. Crowder Nov 05 '19 at 08:45
  • 1
    @T.J.Crowder I have never used strict. [My answer](https://stackoverflow.com/a/58707253/295783) does work with it though.. What are your misgivings? – mplungjan Nov 05 '19 at 08:47
  • 1
    Ahh, does not allow rewriting the arguments – mplungjan Nov 05 '19 at 08:48
  • 2
    @mplungjan - Right. `arguments[0] = x` doesn't change `show` in strict mode. Your answer works because you don't use the formal parameters. – T.J. Crowder Nov 05 '19 at 08:49
1

You can use the arguments object of javascript!! https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

// Each of these strings are padded with intentional and unnecessary whitespace:
let show = "  show ";
let me = " me  ";
let the = " the ";
let bunny = "  bunny   ";

function showMeTheBunny(show, me, the, bunny)
{
    var retString = "";
 for (var i = 0; i < arguments.length; i++) {
       retString += arguments[i].trim() + " ";
    }

 return retString.trim(); 
}
console.log(showMeTheBunny(show, me, the, bunny)); // output: "show me the bunny"
Ashique
  • 345
  • 1
  • 8