How to use a destructuring assignment inside an object - javascript

Is it possible to use a destructuring assignment inside an object?
This works
const test = {a: 'hey', b: 'hello'}
const {a,b} = test;
const destruct = {
a,
b
};
Would like to do this
const test = {a: 'hey', b: 'hello'}
// something like this
const destruct = {
{a,b}: test
};
const destruct = {
{a}: test,
{b}: test
};

If I understand correctly, it seems the spread syntax is a good fit for what you need.
The spread syntax "..." allows you to "spread" the key/value pairs from a source object (ie test) to a target object (ie destruct):
const test = {
a: 'hey',
b: 'hello',
c: 'goodbye'
}
const destruct = {
// {a,b}: test <-- invalid syntax
...test // equivalent using the "spread" syntax
};
console.log(destruct)
Additionally, if you wanted to select a subset of keys from a source object and spread those into a target object then this can be achieved by the following:
const test = {
a: 'hey',
b: 'hello',
c: 'goodbye'
}
/* Spread subset of keys from source object to target object */
const welcomeOnly = {
...({ a, b } = test, { a, b })
}
console.log('exclude goodbye, show welcomes only:', welcomeOnly);
The second example works by destructing the source object (ie test) into an object, with the subset of keys that we want (a and b).
In the scope of that expression (ie everything between the ( and )), these keys are accessible as local variables. We take advantage of this, and pass those to a new object (ie { a, b }). Because the new object is declared after the ,, it is returned as the result of the expression.

If you are trying to take a subset of properties you can use the rest operator
const test = {
a: 'hey',
b: 'hello',
c: 'goodbye'
};
const { c, ...destruct } = test;
console.log(destruct);
This assigns c to a const and the the left over properties are assigned to the const destruct. List all the unwanted properties first and then the left over properties are caught with the rest operator.
Works with arrays as well.
const test = ['hey', 'hello', 'goodbye'];
const [ first, ...rest ] = test;
console.log(rest);

You can try to work like this for destructuring arrays!
let abc = {
a: 'hello',
b: 'hey',
c: 'hi, there!'
}
let {a: x, b:y, c:z} = abc;
console.log(x,y,z)
// "hello"
"hey"
"hi, there!"

Related

Destructure from dynamic key

Suppose I have some key-value object. I want to destructure dynamically from some key such that I can remove it and just get the remaining items in a new object.
const omit = (obj, key) => {
const { [key], ...rest } = obj // Syntax error
return rest
}
omit({ b: 1, c: 2, d: 3 }, 'd')
// desired output { b: 1, c: 2 }
Is there a way to do that?
Disclaimer: I know there are lots of workarounds but would like to do it with destructuring.
In order to destructure on a dynamic key you will need to provide an alias for JS to bind that value to.
Firefox even gives you a helpful error message here:
const omit = (obj, key) => {
const { [key]: _, ...rest } = obj
// CHANGE -----^
return rest
}
console.log(omit({ b: 1, c: 2, d: 3 }, 'd'))
You can rename the variables when destructuring, and the left side (preexisting name) can be in brackets like you want.
let {[key]: omitted, ...rest} = a;

How to combine objects with objects.assign?

My simple code
const ob1 = {
a: 'pokushevski',
b: '2001',
};
const obj2 = {
obj1: {},
c: '1999',
};
const result = Object.assign(ob1, obj2);
console.log(result);
console.log(Object.getOwnPropertyNames(result));
Output
{ a: 'pokushevski', b: '2001', obj1: {}, c: '1999' }
[ 'a', 'b', 'obj1', 'c' ]
It seems that obj1 in result appears just as any other attribute,without having any reference to const obj1.
Why?
What you are doing right now is basically merging ob1 (without 'j') with obj2 (with 'j'), and since obj1 (with 'j') is an empty object inside of obj2, it gets added as a property on the resulting merged object.
What else did you expect, and can we help in getting you there?
Maybe you actually made a typo and wanted the first object ob1 to be named obj1 instead, then to be used as a property within obj2 and finally merge the two objects?
If so you co do:
const obj1 = {
a: 'pokushevski',
b: '2001',
};
const obj2 = {
obj1, // shorthand syntax, property will be named the same as the const
c: '1999',
};
// avoid mutation by using a new object as the target
const result = Object.assign({}, obj1, obj2);
// Display result and property names
console.log(result);
console.log(Object.getOwnPropertyNames(result));
If you only wanted to add obj1 within obj2 you don't need Object.assign
Watch out for what's mutable
With the code above, the original obj1 gets modified whenever you update result.obj1 properties. Try to update result.obj1.a and then console.log(obj1)
If you want to prevent this, you can use destructuring like so:
const obj1 = {
a: 'pokushevski',
b: '2001',
};
// Create a shallow copy of `obj1` to prevent mutating the original
// object by updating `obj2.obj1` properties
const obj2 = {
obj1: {...obj1},
c: '1999',
};
// Avoid mutating the original `obj1` by using a new object as the target
const result = Object.assign({}, obj1, obj2);
// Display result and property names
console.log(result);
console.log(Object.getOwnPropertyNames(result))
If you really want to keep using Object.assign instead of destructuring you can replace obj1: {...obj1} by obj1: Object.assign({}, obj1)
I guess that you want ob1 to be obj1 inside obj2
Then this is a way to do it:
const ob1 = {
a: 'pokushevski',
b: '2001',
};
const obj2 = {
obj1: {},
c: '1999',
};
const result = Object.assign({}, obj2);
Object.assign(result.obj1, ob1);
console.log(result);
console.log(Object.getOwnPropertyNames(result));

How to use functions and their values as parameters?

I want an object to call a function defined in another object or JSON (as a string or reference), with a variable number of values also defined there.
Here's a pseudo-code example of what I'm trying to do:
// function name and variable-length values definition
const definition = {
functionName: "function1",
values: [ 1, "foo", 3.14 ]
}
// objectA calling the function with the values
// objectA.definedFunction(definedValues);
// objectA.[functionName]([val1], [val2], ..., [valN]);
objectA.function1(1, "foo", 3.14);
Note: objectA may/should? reference the definition in a member variable.
How can that be achieved?
And is it possible to expand that so that function1 is a member function of another object that is also defined in definition?
There are two mechanisms you need.
First the square bracket notation to access object properties:
objectA[definition.functionName]; // this will return the function you want
// This is the same as objectA.function1
Second you want to pass an array as parameter list. For that you can use Function.prototype.apply which expects the argument list in the form of an array:
objectA[definition.functionName].apply(objectA, definition.values);
// This is the same as objectA.function1(1, "foo", 3.14);
string to function: Function
const fx1 = Function(definition.functionString)
const fx2 = objectA[definition.functionName]
there has serval way to call fx, depend on how fx handle parameter
fx.apply(null, definition.values)
fx(...definition.values)
fx(definition.values)
If you have an object (i.e. dictionary) of functions and their arguments' values, you can get the function simply by accessing its matching value in the dictionary.
Then, in order to use its arguments, you can use the spread operator:
const dictionary = {
function1: { // For example
definition: (a, b, c) => `{ a: ${a}, b: ${b}, c: ${c} }`,
values: [1, "foo", 3.14],
},
};
function callFunctionByName(name) {
const currFunction = dictionary[name];
const { definition, values } = currFunction;
return definition(...values);
}
console.log(callFunctionByName('function1'));
let objA = {
function1: function(a, b, c) {
console.log(a)
console.log(b);
console.log(c);
}
}
const definition = {
functionName: "function1",
values: [ 1, "foo", 3.14 ]
}
objA[definition.functionName].apply(null, definition.values);
//Second approach if it function1 is not a key of objA
function function1(first, sec, third) {
console.log(first);
console.log(sec);
console.log(third);
}
const definition = {
functionName: "function1",
values: [ 1, "foo", 3.14 ]
}
eval(`${definition.functionName}(${definition.values[0]}, "${definition.values[1]}", ${definition.values[2]})`);

Prefer destructuring - already exisiting variable

my linter is giving me trouble about destructuring.
When I'm trying to destructure, it makes me an error, like in the following snippet :
const data = {
status: 'example',
};
let status = 'foo';
{
status,
} = data;
console.log(status);
Is there any ways to use destructuration when the variable already exists?
Using let again :
const data = {
status: 'example',
};
let status = 'foo';
let {
status,
} = data;
console.log(status);
Add parenthesis around destructuring
From the documentation: Assignment without declaration
The parentheses ( ... ) around the assignment statement are required when using object literal destructuring assignment without a declaration.
{a, b} = {a: 1, b: 2} is not valid stand-alone syntax, as the {a, b} on the left-hand side is considered a block and not an object literal.
However, ({a, b} = {a: 1, b: 2}) is valid, as is var {a, b} = {a: 1, b: 2}
Your ( ... ) expression needs to be preceded by a semicolon or it may be used to execute a function on the previous line.
const data = {
status: 'example',
};
let status = 'foo';
({ status } = data);
console.log(status);

reconstruct partial deconstructed object es6

I am looking for the most concise way to have a new object out of the fields of the deconstructed one.
let obj = {
a: 1,
b: 2,
c: null
}
Currently I have:
let {a, c} = obj;
let data = {a, c}
What I wished I would be having:
let data = {a, c} = obj;
// but data actually becomes {a, b, c}
// and not {a, b} as I wished it to be.
Although your code looks fine may be if your task consists in cherrypicking keys and put it in another object destructuring is not the best approach:
const object = { a: 5, b: 6, c: 7 };
const picked = (({ a, c }) => ({ a, c }))(object);
console.log(picked)
You can define a function that will provide the destructured object as the return value, and assign the call to data:
const obj = {
a: 1,
b: 2,
c: null
}
const partial = ({ a, c }) => ({ a, c })
const data = partial(obj)
console.log(data)
Unfortunately this isn't possible in one line without some setup, but the setup is worthwhile if you are creating the same partial object a lot of places in your source.
Rather than rely on destructuring for this, you can implement a version of the commonly found "pick" function, that accepts as input an object and an array of keys to pull out of that object:
function pick(obj, keys) {
return keys.reduce((memo, key) => {
memo[key] = obj[key];
return memo;
}, {});
}
const obj = { a: 1, b: 2, c: 3 }
const data = pick(obj, ['a', 'b']);
console.log(data); // { a: 1, b: 2}
Normally I would consider performance less important than readability, which is highly subjective. But in this case, both the pick solution above and the one-liners are orders of magnitude slower than your original two-liner, though pick wins out over the one-liner by a comparatively small margin: https://jsperf.com/testaagwt14124oih1oij

Categories