ES6 destructuring with expression [duplicate] - ecmascript-6

This works…
const { prop1:val1, prop2:val2 ) = req.query
val1 = val1.toLowerCase()
Though, I'm more inclined to do something like
const { prop1.toLowerCase():val1, prop2:val2 } = req.query
or
const { prop1:val1.toLowerCase(), prop2:val2 } = req.query
neither of which work. Is there a syntax similar to this or must manipulations be done outside of the destructing assignment?

No, this is not possible. A destructuring assignment does only assign, it does not do arbitrary transformations on the value. (Setters are an exception, but they would only complicate this).
I would recommend to write
const { prop1, prop2:val2 ) = req.query;
const val1 = prop1.toLowerCase();
or, in one statement:
const { prop1, prop2:val2 ) = req.query, val1 = prop1.toLowerCase();

The trouble with the temporary variable solutions is that they introduce different versions of the same data into the scope, which can lead to bugs.
This solution creates a utility function that receives the object to be destructured as well as a second object that is a mapping of property names to transformation functions. It's a little more verbose, but does the trick.
// Utility functions to perform specified transformations on an object
function transformProps(obj, trans) {
return Object.assign({}, obj, ...Object.entries(trans).map(([prop, fn]) =>
prop in obj ? {[prop]: fn(obj[prop])} : null
));
}
const { prop1:val1, prop2:val2 } = transformProps(
{prop1: "FOO", prop2: "BAR"},
{prop1: v => v.toLowerCase()} // Transformations to be made
);
console.log(val1, val2);

Related

Get the keys of the first object JSON [duplicate]

Is there an elegant way to access the first property of an object...
where you don't know the name of your properties
without using a loop like for .. in or jQuery's $.each
For example, I need to access foo1 object without knowing the name of foo1:
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
var obj = { first: 'someVal' };
obj[Object.keys(obj)[0]]; //returns 'someVal'
Object.values(obj)[0]; // returns 'someVal'
Using this you can access also other properties by indexes. Be aware tho! Object.keys or Object.values return order is not guaranteed as per ECMAScript however unofficially it is by all major browsers implementations, please read https://stackoverflow.com/a/23202095 for details on this.
Try the for … in loop and break after the first iteration:
for (var prop in object) {
// object[prop]
break;
}
You can also do Object.values(example)[0].
You can use Object.values() to access values of an object:
var obj = { first: 'someVal' };
Object.values(obj)[0]; // someVal
Use Object.keys to get an array of the properties on an object. Example:
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
var keys = Object.keys(example); // => ["foo1", "foo2", "foo3"] (Note: the order here is not reliable)
Documentation and cross-browser shim provided here. An example of its use can be found in another one of my answers here.
Edit: for clarity, I just want to echo what was correctly stated in other answers: the key order in JavaScript objects is undefined.
A one-liner version:
var val = example[function() { for (var k in example) return k }()];
There isn't a "first" property. Object keys are unordered.
If you loop over them with for (var foo in bar) you will get them in some order, but it may change in future (especially if you add or remove other keys).
The top answer could generate the whole array and then capture from the list. Here is an another effective shortcut
var obj = { first: 'someVal' };
Object.entries(obj)[0][1] // someVal
Solution with lodash library:
_.find(example) // => {name: "foo1"}
but there is no guarantee of the object properties internal storage order because it depends on javascript VM implementation.
Here is a cleaner way of getting the first key:
var object = {
foo1: 'value of the first property "foo1"',
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
let [firstKey] = Object.keys(object)
console.log(firstKey)
console.log(object[firstKey])
if someone prefers array destructuring
const [firstKey] = Object.keys(object);
No. An object literal, as defined by MDN is:
a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}).
Therefore an object literal is not an array, and you can only access the properties using their explicit name or a for loop using the in keyword.
To get the first key name in the object you can use:
var obj = { first: 'someVal' };
Object.keys(obj)[0]; //returns 'first'
Returns a string, so you cant access nested objects if there were, like:
var obj = { first: { someVal : { id : 1} }; Here with that solution you can't access id.
The best solution if you want to get the actual object is using lodash like:
obj[_.first(_.keys(obj))].id
To return the value of the first key, (if you don't know exactly the first key name):
var obj = { first: 'someVal' };
obj[Object.keys(obj)[0]]; //returns 'someVal'
if you know the key name just use:
obj.first
or
obj['first']
This has been covered here before.
The concept of first does not apply to object properties, and the order of a for...in loop is not guaranteed by the specs, however in practice it is reliably FIFO except critically for chrome (bug report). Make your decisions accordingly.
I don't recommend you to use Object.keys since its not supported in old IE versions. But if you really need that, you could use the code above to guarantee the back compatibility:
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
}})()};
Feature Firefox (Gecko)4 (2.0) Chrome 5 Internet Explorer 9 Opera 12 Safari 5
More info: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
But if you only need the first one, we could arrange a shorter solution like:
var data = {"key1":"123","key2":"456"};
var first = {};
for(key in data){
if(data.hasOwnProperty(key)){
first.key = key;
first.content = data[key];
break;
}
}
console.log(first); // {key:"key",content:"123"}
If you need to access "the first property of an object", it might mean that there is something wrong with your logic. The order of an object's properties should not matter.
A more efficient way to do this, without calling Object.keys() or Object.values() which returns an array:
Object.prototype.firstKey = function () {
for (const k in this) {
if (Object.prototype.hasOwnProperty.call(this, k)) return k;
}
return null;
};
Then you can use it like:
const obj = {a: 1, b: 2, c: 3}
console.log(obj.firstKey()) //=> 'a'
This doesn't necessarily return the first key, see Elements order in a "for (… in …)" loop
we can also do with this approch.
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
Object.entries(example)[0][1];
This is an old question but most of the solutions assume that we know the attribute's name which it is not the case for example if you are trying to visualize data from files that the user can upload or similar cases.
This is a simple function that I use and works in both cases that you know the variable and if not it will return the first attribute of the object (sorted alphabetically)
The label function receives an object d and extract the key if exits, otherwise returns the first attribute of the object.
const data = [
{ label: "A", value: 10 },
{ label: "B", value: 15 },
{ label: "C", value: 20 },
{ label: "D", value: 25 },
{ label: "E", value: 30 }
]
const keys = ['label', 0, '', null, undefined]
const label = (d, k) => k ? d[k] : Object.values(d)[0]
data.forEach(d => {
console.log(`first: ${label(d)}, label: ${label(d, keys[0])}`)
})
keys.forEach(k => {
console.log(`label of ${k}: ${label(data[0], k)}`)
})
For values like 0, '', null, and undefined will return the first element of the array.
this is my solution
const dataToSend = {email:'king#gmail.com',password:'12345'};
const formData = new FormData();
for (let i = 0; i < Object.keys(dataToSend).length; i++) {
formData.append(Object.keys(dataToSend)[i],
Object.values(dataToSend)[i]);
}
console.log(formData);
Any reason not to do this?
> example.map(x => x.name);
(3) ["foo1", "foo2", "foo3"]
Basic syntax to iterate through key-value gracefully
const object1 = {
a: 'somestring',
b: 42
};
for (const [key, value] of Object.entries(object1)) {
console.log(`${key}: ${value}`);
}
// expected output:
// "a: somestring"
// "b: 42"
As others have pointed out, if the order of properties is important, storing them in an object is not a good idea. Instead, you should use an array via square brackets. E.g.,
var example = [ {/* stuff1 */}, { /* stuff2 */}, { /* stuff3 */}];
var first = example[0];
Note that you lose the 'foo' identifiers. But you could add a name property to the contained objects:
var example = [
{name: 'foo1', /* stuff1 */},
{name: 'foo2', /* stuff2 */},
{name: 'foo3', /* stuff3 */}
];
var whatWasFirst = example[0].name;
For those seeking an answer to a similar question, namely: "How do I find one or more properties that match a certain pattern?", I'd recommend using Object.keys(). To extend benekastah's answer:
for (const propName of Object.keys(example)) {
if (propName.startsWith('foo')) {
console.log(`Found propName ${propName} with value ${example[propName]}`);
break;
}
}

Mapping over a const variable and returning to the value of an input [duplicate]

I'm trying to access a property of an object using a dynamic name. Is this possible?
const something = { bar: "Foobar!" };
const foo = 'bar';
something.foo; // The idea is to access something.bar, getting "Foobar!"
There are two ways to access properties of an object:
Dot notation: something.bar
Bracket notation: something['bar']
The value between the brackets can be any expression. Therefore, if the property name is stored in a variable, you have to use bracket notation:
var something = {
bar: 'foo'
};
var foo = 'bar';
// both x = something[foo] and something[foo] = x work as expected
console.log(something[foo]);
console.log(something.bar)
This is my solution:
function resolve(path, obj) {
return path.split('.').reduce(function(prev, curr) {
return prev ? prev[curr] : null
}, obj || self)
}
Usage examples:
resolve("document.body.style.width")
// or
resolve("style.width", document.body)
// or even use array indexes
// (someObject has been defined in the question)
resolve("part.0.size", someObject)
// returns null when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})
In javascript we can access with:
dot notation - foo.bar
square brackets - foo[someVar] or foo["string"]
But only second case allows to access properties dynamically:
var foo = { pName1 : 1, pName2 : [1, {foo : bar }, 3] , ...}
var name = "pName"
var num = 1;
foo[name + num]; // 1
// --
var a = 2;
var b = 1;
var c = "foo";
foo[name + a][b][c]; // bar
Following is an ES6 example of how you can access the property of an object using a property name that has been dynamically generated by concatenating two strings.
var suffix = " name";
var person = {
["first" + suffix]: "Nicholas",
["last" + suffix]: "Zakas"
};
console.log(person["first name"]); // "Nicholas"
console.log(person["last name"]); // "Zakas"
This is called computed property names
You can achieve this in quite a few different ways.
let foo = {
bar: 'Hello World'
};
foo.bar;
foo['bar'];
The bracket notation is specially powerful as it let's you access a property based on a variable:
let foo = {
bar: 'Hello World'
};
let prop = 'bar';
foo[prop];
This can be extended to looping over every property of an object. This can be seem redundant due to newer JavaScript constructs such as for ... of ..., but helps illustrate a use case:
let foo = {
bar: 'Hello World',
baz: 'How are you doing?',
last: 'Quite alright'
};
for (let prop in foo.getOwnPropertyNames()) {
console.log(foo[prop]);
}
Both dot and bracket notation also work as expected for nested objects:
let foo = {
bar: {
baz: 'Hello World'
}
};
foo.bar.baz;
foo['bar']['baz'];
foo.bar['baz'];
foo['bar'].baz;
Object destructuring
We could also consider object destructuring as a means to access a property in an object, but as follows:
let foo = {
bar: 'Hello World',
baz: 'How are you doing?',
last: 'Quite alright'
};
let prop = 'last';
let { bar, baz, [prop]: customName } = foo;
// bar = 'Hello World'
// baz = 'How are you doing?'
// customName = 'Quite alright'
You can do it like this using Lodash get
_.get(object, 'a[0].b.c');
UPDATED
Accessing root properties in an object is easily achieved with obj[variable], but getting nested complicates things. Not to write already written code I suggest to use lodash.get.
Example
// Accessing root property
var rootProp = 'rootPropert';
_.get(object, rootProp, defaultValue);
// Accessing nested property
var listOfNestedProperties = [var1, var2];
_.get(object, listOfNestedProperties);
Lodash get can be used in different ways, the documentation lodash.get
To access a property dynamically, simply use square brackets [] as follows:
const something = { bar: "Foobar!" };
const userInput = 'bar';
console.log(something[userInput])
The problem
There's a major gotchya in that solution! (I'm surprised other answers have not brought this up yet). Often you only want to access properties that you've put onto that object yourself, you don't want to grab inherited properties.
Here's an illustration of this issue. Here we have an innocent-looking program, but it has a subtle bug - can you spot it?
const agesOfUsers = { sam: 16, sally: 22 }
const username = prompt('Enter a username:')
if (agesOfUsers[username] !== undefined) {
console.log(`${username} is ${agesOfUsers[username]} years old`)
} else {
console.log(`${username} is not found`)
}
When prompted for a username, if you supply "toString" as a username, it'll give you the following message: "toString is function toString() { [native code] } years old". The issue is that agesOfUsers is an object, and as such, automatically inherits certain properties like .toString() from the base Object class. You can look here for a full list of properties that all objects inherit.
Solutions
Use a Map data structure instead. The stored contents of a map don't suffer from prototype issues, so they provide a clean solution to this problem.
const agesOfUsers = new Map()
agesOfUsers.set('sam', 16)
agesOfUsers.set('sally', 2)
console.log(agesOfUsers.get('sam')) // 16
Use an object with a null prototype, instead of the default prototype. You can use Object.create(null) to create such an object. This sort of object does not suffer from these prototype issues, because you've explicitly created it in a way that it does not inherit anything.
const agesOfUsers = Object.create(null)
agesOfUsers.sam = 16
agesOfUsers.sally = 22;
console.log(agesOfUsers['sam']) // 16
console.log(agesOfUsers['toString']) // undefined - toString was not inherited
You can use Object.hasOwn(yourObj, attrName) to first check if the dynamic key you wish to access is directly on the object and not inherited (learn more here). This is a relatively newer feature, so check the compatibility tables before dropping it into your code. Before Object.hasOwn(yourObj, attrName) came around, you would achieve this same effect via Object.prototype.hasOwnProperty.call(yourObj, attrName). Sometimes, you might see code using yourObj.hasOwnProperty(attrName) too, which sometimes works but it has some pitfalls that you can read about here.
// Try entering the property name "toString",
// you'll see it gets handled correctly.
const user = { name: 'sam', age: 16 }
const propName = prompt('Enter a property name:')
if (Object.hasOwn(user, propName)) {
console.log(`${propName} = ${user[propName]}`)
} else {
console.log(`${propName} is not found`)
}
If you know the key you're trying to use will never be the name of an inherited property (e.g. maybe they're numbers, or they all have the same prefix, etc), you can choose to use the original solution.
I came across a case where I thought I wanted to pass the "address" of an object property as data to another function and populate the object (with AJAX), do lookup from address array, and display in that other function. I couldn't use dot notation without doing string acrobatics so I thought an array might be nice to pass instead. I ended-up doing something different anyway, but seemed related to this post.
Here's a sample of a language file object like the one I wanted data from:
const locs = {
"audioPlayer": {
"controls": {
"start": "start",
"stop": "stop"
},
"heading": "Use controls to start and stop audio."
}
}
I wanted to be able to pass an array such as: ["audioPlayer", "controls", "stop"] to access the language text, "stop" in this case.
I created this little function that looks-up the "least specific" (first) address parameter, and reassigns the returned object to itself. Then it is ready to look-up the next-most-specific address parameter if one exists.
function getText(selectionArray, obj) {
selectionArray.forEach(key => {
obj = obj[key];
});
return obj;
}
usage:
/* returns 'stop' */
console.log(getText(["audioPlayer", "controls", "stop"], locs));
/* returns 'use controls to start and stop audio.' */
console.log(getText(["audioPlayer", "heading"], locs));
ES5 // Check Deeply Nested Variables
This simple piece of code can check for deeply nested variable / value existence without having to check each variable along the way...
var getValue = function( s, context ){
return Function.call( context || null, 'return ' + s )();
}
Ex. - a deeply nested array of objects:
a = [
{
b : [
{
a : 1,
b : [
{
c : 1,
d : 2 // we want to check for this
}
]
}
]
}
]
Instead of :
if(a && a[0] && a[0].b && a[0].b[0] && a[0].b[0].b && a[0].b[0].b[0] && a[0].b[0].b[0].d && a[0].b[0].b[0].d == 2 ) // true
We can now :
if( getValue('a[0].b[0].b[0].d') == 2 ) // true
Cheers!
Others have already mentioned 'dot' and 'square' syntaxes so I want to cover accessing functions and sending parameters in a similar fashion.
Code jsfiddle
var obj = {method:function(p1,p2,p3){console.log("method:",arguments)}}
var str = "method('p1', 'p2', 'p3');"
var match = str.match(/^\s*(\S+)\((.*)\);\s*$/);
var func = match[1]
var parameters = match[2].split(',');
for(var i = 0; i < parameters.length; ++i) {
// clean up param begninning
parameters[i] = parameters[i].replace(/^\s*['"]?/,'');
// clean up param end
parameters[i] = parameters[i].replace(/['"]?\s*$/,'');
}
obj[func](parameters); // sends parameters as array
obj[func].apply(this, parameters); // sends parameters as individual values
I asked a question that kinda duplicated on this topic a while back, and after excessive research, and seeing a lot of information missing that should be here, I feel I have something valuable to add to this older post.
Firstly I want to address that there are several ways to obtain the value of a property and store it in a dynamic Variable. The first most popular, and easiest way IMHO would be:
let properyValue = element.style['enter-a-property'];
however I rarely go this route because it doesn't work on property values assigned via style-sheets. To give you an example, I'll demonstrate with a bit of pseudo code.
let elem = document.getElementById('someDiv');
let cssProp = elem.style['width'];
Using the code example above; if the width property of the div element that was stored in the 'elem' variable was styled in a CSS style-sheet, and not styled inside of its HTML tag, you are without a doubt going to get a return value of undefined stored inside of the cssProp variable. The undefined value occurs because in-order to get the correct value, the code written inside a CSS Style-Sheet needs to be computed in-order to get the value, therefore; you must use a method that will compute the value of the property who's value lies within the style-sheet.
Henceforth the getComputedStyle() method!
function getCssProp(){
let ele = document.getElementById("test");
let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}
W3Schools getComputedValue Doc This gives a good example, and lets you play with it, however, this link Mozilla CSS getComputedValue doc talks about the getComputedValue function in detail, and should be read by any aspiring developer who isn't totally clear on this subject.
As a side note, the getComputedValue method only gets, it does not set. This, obviously is a major downside, however there is a method that gets from CSS style-sheets, as well as sets values, though it is not standard Javascript.
The JQuery method...
$(selector).css(property,value)
...does get, and does set. It is what I use, the only downside is you got to know JQuery, but this is honestly one of the very many good reasons that every Javascript Developer should learn JQuery, it just makes life easy, and offers methods, like this one, which is not available with standard Javascript.
Hope this helps someone!!!
For anyone looking to set the value of a nested variable, here is how to do it:
const _ = require('lodash'); //import lodash module
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// => 4
Documentation: https://lodash.com/docs/4.17.15#set
Also, documentation if you want to get a value: https://lodash.com/docs/4.17.15#get
You can do dynamically access the property of an object using the bracket notation. This would look like this obj[yourKey] however JavaScript objects are really not designed to dynamically updated or read. They are intended to be defined on initialisation.
In case you want to dynamically assign and access key value pairs you should use a map instead.
const yourKey = 'yourKey';
// initialise it with the value
const map1 = new Map([
['yourKey', 'yourValue']
]);
// initialise empty then dynamically assign
const map2 = new Map();
map2.set(yourKey, 'yourValue');
console.log(map1.get(yourKey));
console.log(map2.get(yourKey));
demo object example
let obj = {
name: {
first_name: "Bugs",
last_name: "Founder",
role: "Programmer"
}
}
dotted string key for getting the value of
let key = "name.first_name"
Function
const getValueByDottedKeys = (obj, strKey)=>{
let keys = strKey.split(".")
let value = obj[keys[0]];
for(let i=1;i<keys.length;i++){
value = value[keys[i]]
}
return value
}
Calling getValueByDottedKeys function
value = getValueByDottedKeys(obj, key)
console.log(value)
output
Bugs
const getValueByDottedKeys = (obj, strKey)=>{
let keys = strKey.split(".")
let value = obj[keys[0]];
for(let i=1;i<keys.length;i++){
value = value[keys[i]]
}
return value
}
let obj = {
name: {
first_name: "Bugs",
last_name: "Founder",
role: "Programmer"
}
}
let key = "name.first_name"
value = getValueByDottedKeys(obj, key)
console.log(value)
I bumped into the same problem, but the lodash module is limited when handling nested properties. I wrote a more general solution following the idea of a recursive descendent parser. This solution is available in the following Gist:
Recursive descent object dereferencing
Finding Object by reference without, strings,
Note make sure the object you pass in is cloned , i use cloneDeep from lodash for that
if object looks like
const obj = {data: ['an Object',{person: {name: {first:'nick', last:'gray'} }]
path looks like
const objectPath = ['data',1,'person',name','last']
then call below method and it will return the sub object by path given
const child = findObjectByPath(obj, objectPath)
alert( child) // alerts "last"
const findObjectByPath = (objectIn: any, path: any[]) => {
let obj = objectIn
for (let i = 0; i <= path.length - 1; i++) {
const item = path[i]
// keep going up to the next parent
obj = obj[item] // this is by reference
}
return obj
}
You can use getter in Javascript
getter Docs
Check inside the Object whether the property in question exists,
If it does not exist, take it from the window
const something = {
get: (n) => this.n || something.n || window[n]
};
You should use JSON.parse, take a look at https://www.w3schools.com/js/js_json_parse.asp
const obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}')
console.log(obj.name)
console.log(obj.age)

Why ES6 destructuring is needed in such as specific cases?

In a react+ES6 tutorial, i saw some usages of destructuring which look like the following and which i don't understand why they're needed:
updateFish = (key, updatedFish) => {
const fishes = {...this.state.fishes};
}
this.state.fishes is spread into a new object : {}
why not simply and directly do this ?
const fishes = this.state.fishes;
in another example, i think the reason would be to write a more concise code :
const updatedFish = {
...this.props.fish,
[event.currentTarrget.name]:event.currentTarget.value
}
but i guess if we would want more optimisation, i think this would be faster :
const updatedFish = this.props.fish;
updatedFish[event.currentTarrget.name] = event.currentTarget.value;

How to alter keys in immutable map?

I've a data structure like this (generated by normalizr):
const data = fromJS({
templates: {
"83E51B08-5F55-4FA2-A2A0-99744AE7AAD3":
{"uuid": "83E51B08-5F55-4FA2-A2A0-99744AE7AAD3", test: "bla"},
"F16FB07B-EF7C-440C-9C21-F331FCA93439":
{"uuid": "F16FB07B-EF7C-440C-9C21-F331FCA93439", test: "bla"}
}
})
Now I try to figure out how to replace the UUIDs in both the key and the value of the template entries. Basically how can I archive the following output:
const data = fromJS({
templates: {
"DBB0B4B0-565A-4066-88D3-3284803E0FD2":
{"uuid": "DBB0B4B0-565A-4066-88D3-3284803E0FD2", test: "bla"},
"D44FA349-048E-4006-A545-DBF49B1FA5AF":
{"uuid": "D44FA349-048E-4006-A545-DBF49B1FA5AF", test: "bla"}
}
})
A good candidate seems to me the .mapEntries() method, but I'm struggling on how to use it ...
// this don't work ... :-(
const result = data.mapEntries((k, v) => {
const newUUID = uuid.v4()
return (newUUID, v.set('uuid', newUUID))
})
Maybe someone can give me a hand here?
mapEntries is the correct method. From the documentation, the mapping function has the following signature:
mapper: (entry: [K, V], index: number, iter: this) => [KM, VM]
This means that the first argument is the entry passed in as an array of [key, value]. Similarly, the return value of the mapper function should be an array of the new key and the new value. So your mapper function needs to look like this:
([k, v]) => {
const newUUID = uuid.v4()
return [newUUID, v.set('uuid', newUUID)]
}
This is equivalent to the following (more explicit) function:
(entry) => {
const key = entry[0]; // note that key isn't actually used, so this isn't necessary
const value = entry[1];
const newUUID = uuid.v4()
return [newUUID, value.set('uuid', newUUID)]
}
One thing to note is that the templates are nested under the templates property, so you can't map data directly -- instead you'll want to use the update function.
data.update('templates', templates => template.mapEntries(...)))
So putting everything together, your solution should look like the following:
const result = data.update('templates', templates =>
templates.mapEntries(([k, v]) => {
const newUUID = uuid.v4()
return [newUUID, v.set('uuid', newUUID)]
})
);

Decypher ES6 const destructuring declaration

Can someone help me decypher this ES6 statement?
const {
isFetching,
lastUpdated,
items: posts
} = postsByReddit[selectedReddit] || {
isFetching: true,
items: []
}
I pulled it from the Redux async example - https://github.com/reactjs/redux/blob/master/examples/async/containers/App.js#L81
The code is simply declaring three constants, getting them from similarly named properties on an object if it is non-empty, otherwise get them from an object literal that acts as default values.
I trust that you are confused over the object like syntax rather than the const keyword.
var|let|const { ... } = ... is an object destructuring declaration.
var|let|const [ ... ] = ... is an array destructuring declaration.
Both are short hand for "break down right hand side and assign to left hand side".
Destructuring can be done on array or object using different brackets.
It can be part of a declaration or as stand-alone assignment.
const { isFetching } = obj; // Same as const isFetching = obj.isFetching
var [ a, b ] = ary; // Same as var a = ary[0], b = ary[1]
[ a ] = [ 1 ]; // Same as a = 1
For object destructuring, you can specify the property name.
For array, you can skip elements by leaving blank commas.
Destructuring can also form a hierarchy and be mixed.
const { items: posts } = obj; // Same as const posts = obj.items
var [ , , c ] = ary; // Same as var c = ary[2]
let { foo: [ { bar } ], bas } = obj; // Same as let bar = obj.foo[0].bar, bas = obj.bas
When destructuring null or undefined, or array destructure on non-iterable, it will throw TypeError.
Otherwise, if a matching part cannot be found, its value is undefined, unless a default is set.
let { err1 } = null; // TypeError
let [ err3 ] = {}; // TypeError
let [ { err2 } ] = [ undefined ]; // TypeError
let [ no ] = []; // undefined
let { body } = {}; // undefined
let { here = this } = {}; // here === this
let { valueOf } = 0; // Surprise! valueOf === Number.prototype.valueOf
Array destructuring works on any "iterable" objects, such as Map, Set, or NodeList.
Of course, these iterable objects can also be destructed as objects.
const doc = document;
let [ a0, a1, a2 ] = doc.querySelectorAll( 'a' ); // Get first three <a> into a0, a1, a2
let { 0: a, length } = doc.querySelectorAll( 'a' ); // Get first <a> and number of <a>
Finally, don't forget that destructuring can be used in any declarations, not just in function body:
function log ({ method = 'log', message }) {
console[ method ]( message );
}
log({ method: "info", message: "This calls console.info" });
log({ message: "This defaults to console.log" });
for ( let i = 0, list = frames, { length } = frames ; i < length ; i++ ) {
console.log( list[ i ] ); // Log each frame
}
Note that because destructuring depends on left hand side to specify how to destructre right hand side,
you cannot use destructring to assign to object properties.
This also excludes the usage of calculated property name in destructuring.
As you have seen, destructuring is a simple shorthand concept that will help you do more with less code.
It is well supported in Chrome, Edge, Firefox, Node.js, and Safari,
so you can start learn and use it now!
For EcmaScript5 (IE11) compatibility, Babel and Traceur transpilers
can turn most ES6/ES7 code into ES5, including destructuring.
If still unclear, feel free to come to StackOverflow JavaScript chatroom.
As the second most popular room on SO, experts are available 24/7 :)
This is an additional response to the already given. Destructuring also supports default values, which enables us to simplify the code:
const {
isFetching = true,
lastUpdated,
items = []
} = postsByReddit[selectedReddit] || {};
Basically:
var isFecthing;
var lastUpdated;
var posts;
if (postsByReddit[selectedReddit]) {
isFecthing = postsByReddit[selectedReddit].isFecthing;
lastUpdated = postsByReddit[selectedReddit].lastUpdated;
posts = postsByReddit[selectedReddit].items.posts;
} else {
isFecthing = true;
items = [];
}