Es6 Destructuring Function Parameter - Naming Root Object

ES6 destructuring function parameter - naming root object

I have the 'options' arguments on too many places myself. I would opt for 1 extra line of code. Not worthy in this example, but a good solution when having destructuring on more lines.

const setupChildClass6 = options => {
const {minVal, maxVal} = options;
rangeSlider.setup(minVal, maxVal);
setupParentClass6(options);
};

Destructure object parameter, but also have reference to the parameter as an object?

arguments isn't available in arrow functions, and this affects how function parameters should be consistently treated in ES6.

If original parameter is used, it should be destructured inside function:

(param) => {
const {name, value} = param;
// ...
}

If several arguments are expected and some argument negotiation takes place (for example, similarly to arguments.length), rest parameter should be used:

(...args) => {
const [param] = args;
// ...
}

Boilerplate variable destructuring has its benefits; it's easier this way to debug param or args at breakpoint even if they aren't currently in use.

Is there a way to both destructure a function parameter, and keep a named reference to the parameter?

No (mostly)


From the grammar:

It's hard to prove a negative, so I had to go to the grammar.

Typescript, as far as I'm aware, does not provide any extra destructuring power that javascript does not, so I'll just answer this for javascript.

In the ES6 grammar, there's no way for a single function parameter to be both destructed and given a name in the parameter list, in one parameter.

If you look at the ES6 grammar for FormalParameter, which is one of the things in an argument list, you'll find it can only be a BindingElement, which is either a SingleNameBinding or a BindingPattern — not both. Binding patterns can only do destructuring and single name bindings can only assign to one value, so there's no way to do both.

(Note the grammar I linked is just a gist someone put on github. I don't think someone would post a misleading ES6 grammar on github, but if you're skeptical you can always check the less convenient official grammar.)

It's possible there's some other wild way to do this that I missed, but I've never seen it before and would be very surprised.


If you really want to...

You're "best way you can think of" is the best way I can think of too. You should do that.

I don't like answering "no", though, so if you really want to get it all in the parameter list, you can do something unpleasant instead. If you do:

function assignAndDestructure(props, { foo, bar } = props) {
// props, foo, and bar will all be assigned
}

which kind of fits your criteria. However, it creates an optional second parameter the caller can abuse to mess up your destructuring. You can hide it by assigning it to a type that doesn't have that parameter in Typescript, but it's still risky.


In summary, there's no good way to do it, but there is a bad way. Go with your mentioned "best you can think of."

Destructure argument object, but leave it available in body function?

IMO, the best method would be to either leave your original code as is, or declare the variables on the first line of the function:

const FieldRange = props => {
const { children, errorFieldName } = props;
return (
<div className={b('field-range', props)}>
{props.children}
{!!errorFieldName && <Field name={errorFieldName}/>}
</div>
);
);

There's a really hacky solution that allows you to keep the concise body, which is to use a second parameter, which is not passed to the function, which defaults to destructured props:

const FieldRange = (props, { children, errorFieldName } = props) => {

But that's quite confusing, I wouldn't recommend it.

destructure a parameter and keep reference to it too

There is no syntax support for this. I guess you could hack around this with something like:

const myFunction = (function() {
function myFunction(myparam, {myprop}) {
// ...
}

return function(myparam) {
return myFunction(myparam, myparam);
};
}());

or even

function myFunction(myparam, {myprop}=myparam) {
// ...
}

but both may be considered too hacky.

Destructuring assignment in function call while preserving the object

TL;DR

Objects - losing properties:

let f = ({ a: x, ...o }) => {
console.log(o);
console.log(x);
};
f({ a: 0, b: 1, c: 2 });
// x is: 0
// o is: { b: 1, c: 2 }

Objects - preserving properties:

let f = (o) => {
let { a: x } = o;
console.log(o);
console.log(x);
};
f({ a: 0, b: 1, c: 2 });
// x is: 0
// o is: { a: 0, b: 1, c: 2 }

Arrays - losing elements:

let f = ([x, ...a]) => {
console.log(a);
console.log(x);
};
f([0, 1, 2]);
// x is: 0
// a is: [1, 2]

Arrays - preserving elements:

let f = (a) => {
let [x] = a;
console.log(a);
console.log(x);
};
f([0, 1, 2 ]);
// x is: 0
// a is: [0, 1, 2]

Note that the examples above that preserve properties put the same object in o (or array in a) that was used when calling the function, not a copy. To use a shallow copy you can use the examples below:

Objects - preserving properties, creating a new object:

let f = ({ ...o }) => {
let { a: x } = o;
console.log(o);
console.log(x);
};
f({ a: 0, b: 1, c: 2 });
// x is: 0
// o is: { a: 0, b: 1, c: 2 }

Arrays - preserving elements, creating a new array:

let f = ([...a]) => {
let [x] = a;
console.log(a);
console.log(x);
};
f([0, 1, 2]);
// x is: 0
// a is: [1, 2]

Explanation

If you want to preserve all of the properties of the original object in o then you need the explicit destructuring step in the body of your function: let { a: x } = o; but if you want to preserve only those properties that were not put into x then you may be able to use the destructuring as described below (in the future when it's supported). See Examples below for details.

Note that I originally assumed that you want destructuring as you would get when destructuring arrays - but maybe that's not what you want - thanks to Karen Grigoryan for pointing it out in the comments.

A syntax that should logically work would be not this:

let f = (o: { a: x }) => {
console.log(o);
console.log(x);
};

but this:

let f = ({ a: x, ...o }) => {
console.log(o);
console.log(x);
};

(But I would be (positively) surprised if that worked natively on any platform today or even in transpilers. This would need support for rest operator in object destructuring combined with unpacking fields from objects passed as function parameters. Theoretically there's no reason it shouldn't work. In practice it likely doesn't.)

Note that ({ a: x, ...o }) => ... when invoked as f({ a: 0, b: 1 }) would put only { b: 1 } in o and would put 0 in x - just like ([x, ...a]) => ... when invoked as f([0, 1]) would put only [1] in a and would put 0 in x.

This means that using destructuring with rest parameters - for objects and arrays alike - would not preserve the entire array or object in the rest variable but only that data that was not explicitly captured otherwise.

This means that no matter if you're destructuring arrays or objects, you need to put the explicit destructuring step in the body of your functions instead of relying on the parameter syntax if you want to have the original array or object intact.

See:

  • Rest_in_Object_Destructuring on MDN


Related Topics



Leave a reply



Submit