I am curious about javascript destructuring - javascript

The destructuring is one of the javascript syntax
This have been used like this.
const obj = { a: { A: 1, B: 2 } };
const { a } = obj // this is obj.a
const { B } = a // this is obj.a.B
the thing that I want to know is destructuring can save memory?

Related

How to use object rest operator to omit properties dynamically

I'm using the ES7 Object Rest Operator to Omit Properties from an object, but I'd like to make it more flexible so that I can dynamically provide the list of properties to exclude.
const myObject = {
a: 1,
b: 2,
c: 3
};
const { a, ...noA } = myObject;
console.log(noA); // => { b: 2, c: 3 }
Is there a way to make this more dynamic such that I can call a function and provide an array of properties to exclude instead of the hardcoded approach taken with properties a and b in this example?
Ideally I could have something along these lines -- but this syntax is invalid:
function omitProperties(myObj, fieldsToExclude) {
const { ...fieldsToExclude, ...noA } = myObj;
console.log(noA); // => { b: 2, c: 3 }
}
omitProperties(myObject, [`a`]);
You can consider _.omit.
You can also consider the following:
let omitProperties = (props, exclude) => {
let result = { ...props };
for (let propName of exclude) delete result[propName];
return result;
};
There's quite a bit of discussion about this same issue here.

Automatically assign variables when destructuring large objects in ES6 [duplicate]

This question already has answers here:
How do I destructure all properties into the current scope/closure in ES2015?
(5 answers)
Closed 2 years ago.
I think I understand destructuring in ES6 well enough. Example:
const obj = {
foo: 'String1',
bar: 'String2'
}
let { foo, bar } = obj
console.log(foo) //Prints "String1"
Simple enough.
However, I have a large object with a dynamic number of properties with dynamic names. I'd like to be able to assign them automatically.
Example object:
const obj = {
a: 'String1',
b: 'String2',
c: 'String3',
// ....
y: 'String25',
z: 'String26',
}
Instead of declaring each variable individually, I tried:
// Instead of
// { a, b, c, d, so_on, y, z } = obj
// I try:
let { ...obj } = obj
But get this error:
Identifier 'obj' has already been declared
What's a better way to approach this?
As long as the identifier is different than that of the object you're trying to destructure it should work exactly as you intend it to.
const obj = {
a: 'String1',
b: 'String2',
c: 'String3',
// ...
y: 'String25',
z: 'String26',
}
const { a, b, ...rest } = obj
// const a: 'String1'
// const b: 'String2'
// const rest: {
// c: string;
// ...
// y: string;
// z: string;
// }
See this example in the playground.

Printing deepcopy of an object using custom function

I need to print elements of an object which is a deepcopy of another object using custom function. I am able to create deep copy using JSON parse/stringify trick but unable to implement print function.
var obj = {a:1,
b:{
a:2,
c:[1,2,3],
d:{
a:3
}
}
};
const mySnapShot = new Snapshot(object);
mySnapshot.print('a')// 1
.print('b.c') //[1,2,3]
.print('b.a') // 2
Arguments passed in print method are string. Snapshot is a class which contains methods for deep copy and print.
You can use reduce:
var obj = {
a: 1,
b: {
a: 2,
c: [1, 2, 3],
d: {
a: 3
}
}
};
function print(path) {
const pathTokens = path.split('.');
const pathValue = pathTokens.reduce((subObj, pathToken) => {
return subObj && subObj[pathToken] || null
}, obj);
return pathValue;
}
console.log(print('a')) // 1
console.log(print('b.c')) //[1,2,3]
console.log(print('b.a')) // 2

Functional Programming: How to convert an impure function to a pure function when the input needs to be mutated

How can I create a pure function that updates an object that's been initialized in another function
something like:
parentFunction = (inputs: object[], condtionList: string[]) => {
const newObject = {f1: val1[], f2: val2[], f3: val3[]...}
inputs.forEach(input => {
if(condition1){
updateNewObject(condtion1, newObject, input, conditionList)
}
.
.
.
}
return newObject
}
The below function is impure as it's updating the newObject (mutating the input) how can I convert it to a pure function?
updateNewObject(condition, newObject, input, conditionList) {
const i = conditionList.indexOf(input.condition)
if(i === 0){
newObject.f1.push(input)
}
else if(i === 1) {
newObject.f2.push(input)
}
.
.
.
}
The above has no return value. It takes the newObject as input and based on some conditionals pushes values to the properties of the newObject. Is there anyway to make the above function pure? or do I have to rethink how I am updating newObject?
Functional programming is not only about purity, it's also about reusability and separation of concerns. It's difficult to write a big complex function, and even harder to test and maintain it. Following functional principles will help us avoid pain and discomfort.
Let's start by isolating the behaviours we care about. We identify functions push, update, and pushKey -
const identity = x =>
x
const push = (a = [], value) =>
a.concat([ value ])
const update = (o = {}, key = "", t = identity) =>
({ ...o, [key]: t(o[key]) })
const pushKey = (o = {}, key = "", value) =>
update(o, key, a => push(a, value))
This allows you to perform basic immutable transformations easily -
const d1 = { a: [1], b: [] }
const d2 = pushKey(d1, "a", 2)
const d3 = pushKey(d2, "b", 3)
const d4 = pushKey(d3, "c", 4)
console.log(d1) // { a: [1], b: [] }
console.log(d2) // { a: [1, 2], b: [] }
console.log(d3) // { a: [1, 2], b: [3] }
console.log(d4) // { a: [1, 2], b: [3], c: [4] }
Expand the snippet below to run the program in your own browser -
const identity = x =>
x
const push = (a = [], value) =>
a.concat([ value ])
const update = (o = {}, key = "", t = identity) =>
({ ...o, [key]: t(o[key]) })
const pushKey = (o = {}, key = "", value) =>
update(o, key, a => push(a, value))
const d1 = { a: [1], b: [] }
const d2 = pushKey(d1, "a", 2)
const d3 = pushKey(d2, "b", 3)
const d4 = pushKey(d3, "c", 4)
console.log(JSON.stringify(d1)) // { a: [1], b: [] }
console.log(JSON.stringify(d2)) // { a: [1, 2], b: [] }
console.log(JSON.stringify(d3)) // { a: [1, 2], b: [3] }
console.log(JSON.stringify(d4)) // { a: [1, 2], b: [3], c: [4] }
This allows you to separate your complex conditional logic into its own function -
const updateByCondition = (o = {}, conditions = [], ...) =>
{ if (...)
return pushKey(o, "foo", someValue)
else if (...)
return pushKey(o, "bar", someValue)
else
return pushKey(o, "default", someValue)
}
The advantages to this approach are numerous. push, update, and pushKey are all very easy to write, test, and maintain, and they're easy to reuse in other parts of our program. Writing updateByCondition was much easier because we had better basic building blocks. It's still difficult to test due to whatever complexity you are trying to encode, however it is much easier to maintain due to separation of concerns.
If you want updateNewObject to be pure, have it create a new object that clones the original, mutate that, and then return the new object.
updateNewObject(condition, oldObject, input, conditionList) {
const newObject = {...oldObject};
const i = conditionList.indexOf(input.condition)
if(i === 0){
newObject.f1 = [...newObject.f1, input];
}
else if(i === 1) {
newObject.f2 = [...newObject.f2, input];
}
.
.
.
return newObject;
}
Note how newObject.f1 = [...newObject.f1, input]; creates a new array - this ensures that we not only don't mutate the object directly, but we don't mutate any of its fields (arrays) and instead create new ones.
Then tweak parentFunction so that it uses the value of each returned updateNewObject call:
parentFunction = (inputs: object[], condtionList: string[]) => {
let newObject = {f1: val1[], f2: val2[], f3: val3[]...}
inputs.forEach(input => {
if(condition1){
newObject = updateNewObject(condtion1, newObject, input, conditionList)
}
.
.
.
}
return newObject
}
Classically, you'd create a new object with a new array with the new entry in it:
if(i === 0){
// v−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−v−− creates new object
newObject = {...newObject, f1: [...newObject.f1, input]}
// ^ ^−−−−−−−−−−−−−−−−−−−−−−^−−− creates new array
}
else if(i === 1) {
// v−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−v−− creates new object
newObject = {...newObject, f2: [...newObject.f2, input]}
// ^ ^−−−−−−−−−−−−−−−−−−−−−−^−−− creates new array
}
Then in parentFunction:
newObject = updateNewObject(condtion1, newObject, input, conditionList)
// ^^^^^^^^^^^^−−−−−−−−−−−−−−−−−−−−−− updates the value being returned
Or the update could be:
const name = i === 0 ? "f1" : (i === 1 ? "f2" : ""));
if (name) {
newObject = {...newObject, [name]: [...newObject[name], input]}
}
...though the nested conditional is a bit meh. :-)
Just copy/map the array to get a new one. Don't mutate the same one.

Is it possible to destructure onto an existing object? (Javascript ES6)

For example if I have two objects:
var foo = {
x: "bar",
y: "baz"
}
and
var oof = {}
and I wanted to transfer the x and y values from foo to oof. Is there a way to do that using the es6 destructuring syntax?
perhaps something like:
oof{x,y} = foo
While ugly and a bit repetitive, you can do
({x: oof.x, y: oof.y} = foo);
which will read the two values of the foo object, and write them to their respective locations on the oof object.
Personally I'd still rather read
oof.x = foo.x;
oof.y = foo.y;
or
['x', 'y'].forEach(prop => oof[prop] = foo[prop]);
though.
IMO this is the easiest way to accomplish what you're looking for:
let { prop1, prop2, prop3 } = someObject;
let data = { prop1, prop2, prop3 };
// data === { prop1: someObject.prop1, ... }
Basically, destructure into variables and then use the initializer shorthand to make a new object. No need for Object.assign
I think this is the most readable way, anyways. You can hereby select the exact props out of someObject that you want. If you have an existing object you just want to merge the props into, do something like this:
let { prop1, prop2, prop3 } = someObject;
let data = Object.assign(otherObject, { prop1, prop2, prop3 });
// Makes a new copy, or...
Object.assign(otherObject, { prop1, prop2, prop3 });
// Merges into otherObject
Another, arguably cleaner, way to write it is:
let { prop1, prop2, prop3 } = someObject;
let newObject = { prop1, prop2, prop3 };
// Merges your selected props into otherObject
Object.assign(otherObject, newObject);
I use this for POST requests a lot where I only need a few pieces of discrete data. But, I agree there should be a one liner for doing this.
EDIT: P.S. -
I recently learned you can use ultra destructuring in the first step to pull nested values out of complex objects! For instance...
let { prop1,
prop2: { somethingDeeper },
prop3: {
nested1: {
nested2
}
} = someObject;
let data = { prop1, somethingDeeper, nested2 };
Plus, you could use spread operator instead of Object.assign when making a new object:
const { prop1, prop2, prop3 } = someObject;
let finalObject = {...otherObject, prop1, prop2, prop3 };
Or...
const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };
No, destructuring does not support member expressions in shorthands but only plain propertynames at the current time. There have been talks about such on esdiscuss, but no proposals will make it into ES6.
You might be able to use Object.assign however - if you don't need all own properties, you still can do
var foo = …,
oof = {};
{
let {x, y} = foo;
Object.assign(oof, {x, y})
}
Other than Object.assign there is the object spread syntax which is a Stage 2 proposal for ECMAScript.
var foo = {
x: "bar",
y: "baz"
}
var oof = { z: "z" }
oof = {...oof, ...foo }
console.log(oof)
/* result
{
"x": "bar",
"y": "baz",
"z": "z"
}
*/
But to use this feature you need to use stage-2 or transform-object-rest-spread plugin for babel. Here is a demo on babel with stage-2
BabelJS plugin
If you are using BabelJS you can now activate my plugin babel-plugin-transform-object-from-destructuring (see npm package for installation and usage).
I had the same issue described in this thread and for me it was very exhausting when you create an object from a destructuring expression, especially when you have to rename, add or remove a property. With this plugin maintaining such scenarios gets much more easier for you.
Object example
let myObject = {
test1: "stringTest1",
test2: "stringTest2",
test3: "stringTest3"
};
let { test1, test3 } = myObject,
myTest = { test1, test3 };
can be written as:
let myTest = { test1, test3 } = myObject;
Array example
let myArray = ["stringTest1", "stringTest2", "stringTest3"];
let [ test1, , test3 ] = myArray,
myTest = [ test1, test3 ];
can be written as:
let myTest = [ test1, , test3 ] = myArray;
It's totally possible. Just not in one statement.
var foo = {
x: "bar",
y: "baz"
};
var oof = {};
({x: oof.x, y: oof.y} = foo); // {x: "bar", y: "baz"}
(Do note the parenthesis around the statement.)
But keep in mind legibility is more important than code-golfing :).
Source: http://exploringjs.com/es6/ch_destructuring.html#sec_assignment-targets
You can just use restructuring for that like this:
const foo = {x:"a", y:"b"};
const {...oof} = foo; // {x:"a", y:"b"}
Or merge both objects if oof has values:
const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)
You can return the destructured object in an arrow function, and use Object.assign() to assign it to a variable.
const foo = {
x: "bar",
y: "baz"
}
const oof = Object.assign({}, () => ({ x, y } = foo));
You can destruct an object assigning directly to another object attribute.
Working example:
let user = {};
[user.name, user.username] = "Stack Overflow".split(' ');
document.write(`
1st attr: ${user.name} <br />
2nd attr: ${user.username}`);
You can work with destructing using variables with the same name of object attribute you want to catch, this way you don't need to do:
let user = { name: 'Mike' }
let { name: name } = user;
Use this way:
let user = { name: 'Mike' }
let { name } = user;
The same way you can set new values to object structures if they have the same attribute name.
Look this working example:
// The object to be destructed
let options = {
title: "Menu",
width: 100,
height: 200
};
// Destructing
let {width: w, height: h, title} = options;
// Feedback
document.write(title + "<br />"); // Menu
document.write(w + "<br />"); // 100
document.write(h); // 200
Try
var a = {a1:1, a2: 2, a3: 3};
var b = {b1:1, b2: 2, b3: 3};
const newVar = (() => ({a1, a2, b1, b2})).bind({...a, ...b});
const val = newVar();
console.log({...val});
// print: Object { a1: 1, a2: 2, b1: 1, b2: 2 }
or
console.log({...(() => ({a1, a2, b1, b2})).bind({...a, ...b})()});
I came up with this method:
exports.pick = function pick(src, props, dest={}) {
return Object.keys(props).reduce((d,p) => {
if(typeof props[p] === 'string') {
d[props[p]] = src[p];
} else if(props[p]) {
d[p] = src[p];
}
return d;
},dest);
};
Which you can use like this:
let cbEvents = util.pick(this.props.events, {onFocus:1,onBlur:1,onCheck:'onChange'});
let wrapEvents = util.pick(this.props.events, {onMouseEnter:1,onMouseLeave:1});
i.e., you can pick which properties you want out and put them into a new object. Unlike _.pick you can also rename them at the same time.
If you want to copy the props onto an existing object, just set the dest arg.
This is kind of cheating, but you can do something like this...
const originalObject = {
hello: 'nurse',
meaningOfLife: 42,
your: 'mom',
};
const partialObject = (({ hello, your }) => {
return { hello, your };
})(originalObject);
console.log(partialObject); // ​​​​​{ hello: 'nurse', your: 'mom' }​​​​​
In practice, I think you'd rarely want to use that though. The following is MUCH more clear... but not nearly as fun.
const partialObject = {
hello: originalObject.hello,
your: originalObject.your,
};
Another completely different route, which includes mucking with the prototype (careful now...):
if (!Object.prototype.pluck) {
Object.prototype.pluck = function(...props) {
return props.reduce((destObj, prop) => {
destObj[prop] = this[prop];
return destObj;
}, {});
}
}
const originalObject = {
hello: 'nurse',
meaningOfLife: 42,
your: 'mom',
};
const partialObject2 = originalObject.pluck('hello', 'your');
console.log(partialObject2); // { hello: 'nurse', your: 'mom' }
This is the most readable and shortest solution I could come up with:
let props = {
isValidDate: 'yes',
badProp: 'no!',
};
let { isValidDate } = props;
let newProps = { isValidDate };
console.log(newProps);
It will output { isValidDate: 'yes' }
It would be nice to some day be able to say something like let newProps = ({ isValidDate } = props) but unfortunately it is not something ES6 supports.
You can use JSON class methods to achieve it as follows
const foo = {
x: "bar",
y: "baz"
};
const oof = JSON.parse(JSON.stringify(foo, ['x','y']));
// output -> {x: "bar", y: "baz"}
Pass properties that need to be added to the resulting object as second argument to stringify function in an array format.
MDN Doc for JSON.stringify
This works in chrome 53.0.2785.89
let foo = {
x: "bar",
y: "baz"
};
let oof = {x, y} = foo;
console.log(`oof: ${JSON.stringify(oof)}`);
//prints oof: { "x": "bar", "y": "baz"}
It's not a beautiful way, nor I recommend it, but it's possible this way, just for knowledge.
const myObject = {
name: 'foo',
surname: 'bar',
year: 2018
};
const newObject = ['name', 'surname'].reduce(
(prev, curr) => (prev[curr] = myObject[curr], prev),
{},
);
console.log(JSON.stringify(newObject)); // {"name":"foo","surname":"bar"}

Categories

Resources