Set only one optional parameter of a JS function with ES6 - javascript

In python, we can do:
func(a, b=1, c=2)
And then call it like that
func(8, c=5)
With ES6, we can declare it in the same way :
func(a, b=1, c=2)
But how to set c without setting b to undefined ?

You can create a function that accepts an object, and get the parameters using destructuring. Now you can pass the parameters in any order you wish:
function fn({ a, b=1, c=2 }) {
console.log({ a, b, c })
}
fn({ a: 8, c: 5 })

Related

Convenient transform of JavaScript method call into function

Is there an easy way to convert a field access or method call into a function that could be passed into e.g. Array.map?
a = {'foo': 1};
b = {'foo': 2};
c = {'foo': 3};
[a, b, c].map(m => m.foo);
Is m => m.foo the best we can do (w/ built-in JS functionality)? Or is there an even shorter way?
One more
[a, b, c].map(({foo}) => foo)

Specify second default argument Javascript

Say I have a function with three arguments, 2 of them having a default value:
function f(a, b=2, c=3){
console.log(a, b, c)
}
If I'm perfectly happy with b's value, is there a way to call f and specify a value for c directly?
In Python I'd do something like f(1, c=5)?
Use cases: if I don't know b's default value or if there are many more arguments it would be cumbersome not to be able to do such a thing
is there a way to call f and specify a value for c directly?
No, JavaScript doesn't have that kind of named parameter.
You can call f using the default for b by giving undefined:
f(1, undefined, 5);
function f(a, b = 2, c = 3){
console.log(a, b, c)
}
f(1, undefined, 5);
Alternately, you can define f differently: Have it accept an object that it destructures into parameters, then call it with an object:
function f({a, b = 2, c = 3}){
console.log(a, b, c)
}
f({a: 1, c: 5});
If you want it to be valid to call it with no object (it's an error with the above), provide a default for the destructured parameter:
function f({a, b = 2, c = 3} = {}){
// -------------------------^^^^^
console.log(a, b, c)
}
You could pass an object with named keys like so:
function f({a, b=2, c=3}){
console.log(a, b, c)
}
f({b: 4})

Can I bypass optional parameters and still set a rest parameter in Javascript?

I have a function with a required parameter (A), some optional parameters (B,C) and a rest parameter (Z)
const doTheThing = (a, b = 'B', c = 'C', ...z) => {
console.log(a, b, c, z);
}
I have cases where I would like to call the function without specifying the optional parameters, but still specify the rest parameter "Z"
doTheThing('A', ...'Z');
Expected Output:
'A', 'B', 'C', 'Z'
Unfortunately, I get the following:
Parsing error: Shorthand property assignments are valid only in destructuring patterns
How do I go about solving this?
JavaScript doesn't allow supplying named parameters or any sort of parameter skipping, so it's not possible to do what you want with the function in its current form. Here are some alternatives, though:
Plain JavaScript approach: a configuration Object as parameter
Instead of accepting multiple parameters
func = (a, b, c) => { /* operate with parameters */ }
func("One", "Two", "Three")
your function will instead accept an object
func = config => { /* operate with config */ }
func({a: "One", b: "Two", c: "Three"})
This is a common pattern in JavaScript because it allows you to almost name your variables and doesn't require you pass them in the correct order.. It makes it easy to pass a large quantity of them and it can also make it easy to default them, too.
const doTheThing = (config) => {
const defaultProperties = {
b: "B",
c: "C"
}
const {a, b, c, ...rest} = Object.assign({}, defaultProperties, config);
const z = Object.values(rest); //extract their values, otherwise you get an object
console.log(a, b, c, z);
}
doTheThing({a: "A", x: "X", y: "Y", z: "Z"});
It is slightly clunky to use with rest parameters but not unworkable.
However, it does mean that it may be harder to see what parameters you can pass and what is required, if you have a large number of them.
Object Oriented approach: Builder pattern
You create a builder object - it serves to hold values until you call the final method at which point it takes all parameters and constructs an object in one go.
This is how more Object Oriented languages handle having a multitude of parameters where you can even have some of them optional. It's not really common to see builders defined like this in JavaScript but it's not too strange, either. If you use classes already or even TypeScript, then this is probably a better fit.
class DoTheThingBuilder {
constructor() {
this.a = null;
this.b = "B";
this.c = "C";
this.z = null;
}
withA(a) {
this.a = a;
return this;
}
withB(b) {
this.b = b;
return this;
}
withC(c) {
this.c = c;
return this;
}
withEverythingElse(...z) {
this.z = z;
return this;
}
doTheActualThing() {
const {a, b, c, z} = this;
console.log(a, b, c, z);
}
}
const builder = new DoTheThingBuilder();
builder
.withA("A")
.withEverythingElse("X", "Y", "Z")
.doTheActualThing();
As you can see, this can be pretty verbose for some simple tasks. It is a big overkill for this example, but perhaps in actual usage, you might find it helps.
I've deviated a bit from the usual approach - normally, you would set all parameters needed with the builder and finally call .build() which constructs an object. In this case, I basically renamed build to doTheActualThing and it's executing the function.
Functional approach: Currying
The concept of currying is quite simple - instead of having one function that accepts several parameters
func = (a, b, c) => { /* operate with parameters */ }
you have a function that takes one parameter, that returns a function that takes the second parameter, that returns another function, etc., until all parameters are satisfied, at which point the full function is executed.
func = a => b => c => { /* operate with parameters */ }
In many ways, this is the functional equivalent of the OO Builder pattern.
const doTheThing = (a) =>
(b = "B") =>
(c = 'C') =>
(...z) => console.log(a, b, c, z);
doTheThing("A")()()("X", "Y", "Z");
This way you can skip the second and third parameter by not supplying them and you'd get the defaults. It's also way shorter than a builder. However, reading the function can be a bit weird.
That is not possible and very error-prone. The point of naming your parameters is to know what they are and in what order they are coming.
You could achieve something similar using object as a function parameter:
const doTheThing = ({ a, b = "B", c = "C", others = {} }) => {
const params = { a, b, c, ...others }; // this will merge your parameters into one object
console.log(params);
}
doTheThing({ a: "A", others: { z: "Z" }});
This will log A, B, C, Z. Demo: https://codepen.io/tomekbuszewski/pen/jQqmNL?editors=0011

Dont understand this javascript function syntax

Can someone please explain this javascript syntax.
What does n: { } mean?
Does it mean that AVSetFocus returns a nobject (which has been given the temporary name, n, which consists of 'fields' t, f and a. t is an object (looks like), f is a function of the object t, and a is an array?
So AVSetFocus is returning an object and a function and an array. Does this function actually call SetFocusToField?
What is this style called?
Bit confused.
function AVSetFocus(d, b) {
return {
n: {
t: FocusMgr,
f: FocusMgr.SetFocusToField,
a: [d, b]
}
}
}
Just also found this:
var FocusMgr;
function FocusMgr_Init() {
FocusMgr = new function () {
this.mCurFocusID = 0;
this.mCurFocusWindowID = 0;
this.mCurFocusElement = null;
this.mOpenedWindow = false;
this.mFocusStk = [];
//etc
}
}
The AvSetFocus() function returns this object:
{
n: {
t: FocusMgr,
f: FocusMgr.SetFocusToField,
a: [d, b]
}
}
The object has one property, "n", which itself refers to another object:
{
t: FocusMgr,
f: FocusMgr.SetFocusToField,
a: [d, b]
}
...which in turn has three properties. "t" refers to (presumably) yet another object, "f" refers to a method of same object "t" refers to, which seems a little redundant since you could access that via ""t, and "a" ends up referring to an array of the two values passed into AvSetFocus() as parameters.
"Does this function actually call SetFocusToField?"
No it doesn't. You might use it something like:
var avsf = AvSetFocus(x, y);
avsf.n.f(); // calls FocusMgr.SetFocusToField()
Or you could do this:
AvSetFocus(x, y).n.f();
As for what the parameters you pass to AvSetFocus() should be, I have no idea - from the code shown there's no way to tell.
Does it mean that AVSetFocus returns a nobject (which has been given
the temporary name, n, which consists of 'fields' t, f and a. t is an
object (looks like), f is a function of the object t, and a is an
array?
{} is the object literal notation. It creates a new object. So yes you are correct.
The f variable is just a reference to the method, but it is not executed.
You can call the function by doing n.f();

Does Python have a way to pass arguments through a function

Javascript has a poorly constructed but convenient "arguments" variable inside every function, such that you can pass arguments through a function like so:
function foo(a, b, c) {
return bar.apply(this, arguments);
}
function bar(a, b, c) {
return [a, b, c];
}
foo(2, 3, 5); // returns [2, 3, 5]
Is there an easy way to do a similar thing in Python?
>>> def foo(*args):
... return args
>>> foo(1,2,3)
(1,2,3)
is that what you want?
Yeah, this is what I should have said.
def foo(*args):
return bar(*args)
You don't need to declare the function with (a,b,c). bar(...) will get whatever foo(...) gets.
My other crummier answer is below:
I was so close to answering "No, it can't easily be done" but with a few extra lines, I think it can.
#cbrauchli great idea using locals(), but since locals() also returns local variables, if we do
def foo(a,b,c):
n = "foobar" # any code that declares local variables will affect locals()
return bar(**locals())
we'll be passing an unwanted 4th argument, n, to bar(a,b,c) and we'll get an error. To solve this, you'd want to do something like arguments = locals() in the very first line i.e.
def foo(a, b, c):
myargs = locals() # at this point, locals only has a,b,c
total = a + b + c # we can do what we like until the end
return bar(**myargs) # turn the dictionary of a,b,c into a keyword list using **
How about using * for argument expansion?
>>> def foo(*args):
... return bar(*(args[:3]))
>>> def bar(a, b, c):
... return [a, b, c]
>>> foo(1, 2, 3, 4)
[1, 2, 3]
I think this most closely resembles your javascript snippet. It doesn't require you to change the function definition.
>>> def foo(a, b, c):
... return bar(**locals())
...
>>> def bar(a, b, c):
... return [a, b, c]
...
>>> foo(2,3,5)
[2, 3, 5]
Note that locals() gets all of the local variables, so you should use it at the beginning of the method and make a copy of the dictionary it produces if you declare other variables. Or you can use the inspect module as explained in this SO post.

Categories