Reputation: 1133
Is there a way to destructure a JS object in-place, instead of assigning the destructured variables to a scope?
Instead of doing this:
const { a, b, c } = obj;
someFunction(a, b, c);
I'd like to do this:
someFunction({a, b, c} from obj);
Or something functionally equivalent.
I'd like to do this in situations with these two stipulations:
I don't want to put the variable names into the enclosing scope.
I don't want to pass the whole object obj
, therefore making the spread operator not an option.
The only option I'm left with is to use
someFunction(obj.a, obj.b, obj.c);
Which is fine in this case, but can lower readability when obj
is instead a long identifier.
Is something like this possible? I tried using assignment in an expression as a workaround, but my IDE complained that it could not find names a
, b
, and c
:
someFunction({a, b, c} = obj);
Upvotes: 13
Views: 9399
Reputation: 1489
This is needed when you can't access or change the function declaration, or simply you don't want to.
const getParamNames = func => {
const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
const ARGUMENT_NAMES = /([^\s,]+)/g;
let fnStr = func.toString().replace(STRIP_COMMENTS, '');
let result = fnStr.slice(fnStr.indexOf('(') + 1,
fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if (result === null)
result = [];
return result;
}
const callFunctionFromObject = (func, obj) => {
let params = getParamNames2(func)
return func(...params.map(prop => obj[prop]))
}
Example usage:
// Function declared somewhere:
var logForStackOverflow = (a, b, c) => console.log(a, b, c)
// Example 1
callFunctionFromObject(logForStackOverflow, {a: 1});
1 undefined undefined
// Example 2
callFunctionFromObject(logForStackOverflow, {b: 1})
undefined 1 undefined
// Example 3
callFunctionFromObject(logForStackOverflow, {b: "hello", c:3, a:[1, 2, 3]})
[1, 2, 3] "hello" 3
Thanks to CertainPerformance's solution.
Upvotes: -2
Reputation: 1224
This how I'd do it:
function foo( { x, y } ) {
console.log( x, y );
}
foo( { y: 1, x: 2 } ); // 2 1
As for the OP's specific request to not pass the whole object (or declare variables in the global scope), destructuring the object to block-scoped variables would be the best way, IMHO.
const obj = { x: 1, y: 2 }
function foo( x, y ) {
console.log( x, y );
}
{ let { x, y } = obj;
foo( x, y ); // 1 2
}
console.log(x) // "ReferenceError: x is not defined
Upvotes: 2
Reputation: 44107
An IIFE should work:
((({ a, b, c }) => someFunction(a, b, c))(obj);
Upvotes: 6
Reputation: 370759
One option is to use .map
to extract the value of each property you want, and spread it into the argument list:
someFunction(
...['a', 'b', 'c'].map(prop => obj[prop])
);
Destructuring requires the creation of intermediate variables, unfortunately, which you don't want.
Upvotes: 10