ES6 Destructing for objects - javascript

I am new to ES6 destructing. I have an object which contains another object. I want to store certain values from the nested object.
For example -
z = {g: 1, h: 2, i: {d1:5, d2:6, d3:7}}
When I do
let { g, i : {d1, d3}, ...less } = z
the less variable only stores h and not d2.
Is there a way to make it so it is
less = {h, i : {d2}}

No there is not. What you could do is
let { g, i: { d1, d3, ...less2 }, ...less } = z
let less = { ...less, i: less2 };
This extracts the remainder and merges them back together while preserving the shape.

No, unfortunately this is not possible.
You can however extract the missing values from i with a second rest spread:
let z = {g: 1, h: 2, i: {d1:5, d2:6, d3:7}};
let { g, i : {d1, d3, ...i_less}, ...rest_less } = z;
let less = { i: i_less, ...rest_less };
console.log(less)

This is my way, hope it could help.
let z = {
g: 1,
h: 2,
i: {
d1:5,
d2:6,
d3:7
}
}
let {g, i: {d1, d3, ...less1}, ...less2} = z
let less = {
i: less1,
...less2,
}
console.log(less); // output: {h: 2, i:{d2:6}}

Related

Dynamically writing data into nested objects in JavaScript

I would like to dynamically write data (in the form of an object) as a value to an object nested inside another object; and to also create the name of the keys on the fly (inside a loop).
My current code looks like this:
data = {'x': 2, 'y': 3}
master_obj = {'useless': {}, 'important': {}}
var block_ind = 0
let trials = 12
let trials_per_block = 4
for (trial_ind=0; trial_ind<trials; trial_ind++) {
// every 4 trials are in a new block
block_ind = trial_ind % trials_per_block == 0 ? trial_ind/trials_per_block : block_ind
master_obj['important']['block_0'+block_ind] = {}
master_obj['important']['block_0'+block_ind]['trial_0'+trial_ind] = data
}
console.log(master_obj)
The output of the code looks like this (run snippet above too):
Whereas the expected output is [multiple trials within a block, not a single one]:
useless: {}
important:
block_00:
trial_00: {x: 2, y:3}
trial_01: {x: 2, y:3}
trial_02: {x: 2, y:3}
trial_03: {x: 2, y:3}
block_01:
trial_04: {x: 2, y:3}
trial_05: {x: 2, y:3}
trial_06: {x: 2, y:3}
trial_07: {x: 2, y:3}
block_02:
trial_08: {x: 2, y:3}
trial_09: {x: 2, y:3}
trial_10: {x: 2, y:3}
trial_11: {x: 2, y:3}
Any and all help and advice is appreciated!
The problem is that you're not copying data, you're just reusing the same object. Another issue is that you're overwriting the object you created previously when you're trying to add another instance to an existing block.
How you copy it is a potentially-complex topic (see this question's answers), but for a shallow copy of just its own, enumerable properties, you can use either spread notation or Object.assign with an object literal, see the *** line below:
const data = {"x": 2, "y": 3}
const master_obj = {"useless": {}, "important": {}}
var block_ind = 0
let trials = 12
let trials_per_block = 4
const important = master_obj.important; // *** No need to repeat this
for (let trial_ind=0; trial_ind<trials; trial_ind++) {
// ^^^−−−− *** Declare your variables
// every 4 trials are in a new block
block_ind = trial_ind % trials_per_block == 0 ? trial_ind/trials_per_block : block_ind
// *** Only create this if it doesn't exist
if (!important["block_0"+block_ind]) {
important["block_0"+block_ind] = {}
}
important["block_0"+block_ind]["trial_0"+trial_ind] = {...data} // ***
}
console.log(master_obj)
Also note that I added const on data and master_obj. Without let, const, or var, your code was falling prey to what I call The Horror of Implicit Globals. Be sure to declare your variables. (I recommend always using const or let, never var.)
For what it's worth, you can use Math.floor(trial_ind / trials_per_block) to determine the block number. Here's that plus a couple of template literals and other constants with descriptive names:
const data = {"x": 2, "y": 3};
const master_obj = {"useless": {}, "important": {}};
const trials = 12;
const trials_per_block = 4;
const important = master_obj.important;
for (let trial_ind = 0; trial_ind < trials; ++trial_ind) {
// Every 4 trials are in a new block
const blockKey = `block_0${Math.floor(trial_ind / trials_per_block)}`;
const trialKey = `trial_0${trial_ind}`;
if (!important[blockKey]) {
important[blockKey] = {};
}
important[blockKey][trialKey] = {...data};
}
console.log(master_obj);

Going through an array of words and returning new array of numbers

I have a huge list of words that I parsed from words.txt file and filtered out numbers, punctuation characters and all word that have uppercase letters. Then I need to go through that array, taking every word and returning the values from letterScores object. As an output I always get NaN and since I am new at JS I have no clue how to make it work.
I also tried to use map() method instead of pushing values into an empty array, but got the same Not a Number output. I believe there should be easier way to achieve the same result that I am not aware of.
var text = fs.readFileSync("./words.txt").toString('utf-8');
var textByLine = text.split("\n")
//--------------------------------------------------------//
const task1 = () =>{
letterScores = {
a:1, e:1, i:1, o:1, u:1, l:1, n:1, s:1, t:1, r:1,
d:2, g:2,
b:3, c:3, m:3, p:3,
f:4, h:4, v:4, w:4, y:4,
k:5,
j:8, x:8,
q:10, z:10
}
let wordScores = []
let filtered = textByLine.filter((word) => !/\W|\d|[A-Z]/.test(word))
filtered.forEach((word) =>{
const newWord = [...word]
sum = 0
for (let letters in newWord){
sum += letterScores[letters]
}
wordScores.push(sum)
})
return wordScores
}
console.log(task1())
I was not sure if you had to split it by line. I left it in if you have to, but it creates a third nested array as you split it by line, then split it by word, but then the word needs to be split into characters for comparison. I have it set for a double nested loop, but left the third loop in if it is absolutely necessary.
Hope it helps
//var text = fs.readFileSync("./words.txt").toString('utf-8');
var text = 'The man ran quickly.\nI do not know why, but he did.';
//var textByLine = text.split("\n");
const task1 = () => {
letterScores = {
a: 1, e: 1, i: 1, o: 1, u: 1, l: 1, n: 1, s: 1, t: 1, r: 1,
d: 2, g: 2,
b: 3, c: 3, m: 3, p: 3,
f: 4, h: 4, v: 4, w: 4, y: 4,
k: 5,
j: 8, x: 8,
q: 10, z: 10
};
let wordScores = [];
//textByLine.forEach(function (words) {
let filtered = text.replace(/[^a-zA-Z0-9 !?]+/g, "");
words = filtered.toLowerCase();
var newLine = words.split(" ");
newLine.forEach(function (word) {
const newWord = word.split("");
sum = 0;
for (var i = 0; i < newWord.length; i++) {
sum += letterScores[newWord[i]];
}
wordScores.push(sum);
});
//});
return wordScores;
};
console.log(task1());

Better way to handle operations with many variables?

I have around 30 values stored as variables:
var a = 1,
b = 2,
c = 3,
...
z = 26,
aa = 27,
ab = 28;
that I want to scale. I do so using an array:
array = [a, b, c];
var scale = 5;
for (var i = 0; i < array.length; i++){
array[i] = array[i] * scale; // Some simple arithmetic
}
To get the new scaled value, I need to reassign my variables.
var a = array[0],
b = array[1],
c = array[2],
...
z = array[26],
aa = array[27],
ab = array[28];
This is cumbersome, even if I use destructuring assignment. What is a better way to manage all the information I have?
Using plain variables you won‘t find a smarter way. I‘d suggest to use objects instead as arrays are anonymous because you access the content by index instead of a name:
let groupA = {
a: 1,
b: 2,
c: 3
}
You can then iterate and multiply via
for (let key in groupA) {
if (groupA.hasOwnProperty(key) {
groupA[key] *= 5;
}
}
but you still can access each field individually
console.log(groupA.a);
You have to reassign anyway, but you can do it in a more concise way:
let a = 1,
b = 2,
c = 3;
([a, b, c] = [a, b, c].map(v => v * 5));
console.log(b);

Default value for object argument

I want to create a function with an object as parameter
The object can have for exemple three keys : x, y, z
All this keys must have default value assignment
I tried this :
function f({x:x, y:y, z: z} = {x:1,y:2,z:3}) {
return x + y + z;
}
But I have a problem
f() // return 6 => OK!
f({x: 2, y: 3, z: 4}) // return 9 => OK!
f({x: 2, y:3}) // return NaN (because z === undefined), I expect 8
How can I do this?
You can assign individual defaults when destructuring objects:
function f({ x = 1, y = 2, z = 3 } = {}) {
return x + y + z
}
console.log(f())
console.log(f({ x: 2, y: 3, z: 4 }))
console.log(f({ x: 2, y:3 }))
See the docs here, which describes array destructuring, but the same applies to objects.
What does destructuring mean? It’s a JavaScript expression that allows us to extract data from arrays, objects, maps and sets into their own variable. It allows us to extract properties from an object or items from an array, multiple at a time.
Short form: The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
Please have a look at this simple code example:
function yourFunction({
x = 1,
y = 2,
z = 3
} = {}) {
return x + y + z
}
out.innerHTML+="<br>" + yourFunction()
out.innerHTML+="<br>" + yourFunction({ x: 3, y: 3, z: 4 })
out.innerHTML+="<br>" + yourFunction({ x: 7, y: 1})
<p id="out">Results: </p>
Have a look at the docs: click

Confused with object properties. How do I not get 'undefined'?

I’m trying to create an array consisting of an object for each letter in the alphabet with two properties. Letter and dd_array. Right now I’m setting dd_array = [], but I would like it to be the corresponding morseDic property.
So for instance _charObjArray[0] = {letter: 'a', dd_array: [0,1]}
Can I get some tips on how to code this best possible??
alpha_array = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
morseDic = {
a: [0,1],
b: [1,0,0,0],
c: [1,0,1,0],
d: [1,0,0],
e: [0],
f: [0,0,1,0],
g: [1,1,0],
h: [0,0,0,0],
i: [0,0],
j: [0,1,1,1],
k: [1,0,1],
l: [0,1,0,0],
m: [1,1],
n: [1,0],
o: [1,1,1],
p: [0,1,1,0],
q: [1,1,0,1],
r: [0,1,0],
s: [0,0,0],
t: [1],
u: [0,0,1],
v: [0,0,0,1],
w: [0,1,1],
x: [1,0,0,1],
y: [1,0,1,1],
z: [1,1,0,0]
}
function _alpha(_char, dd_array) {
this.letter = _char;
this.dd_array = dd_array;
}
var _charObjArray = []
for (i = 0; i < alpha_array.length; i++) {
var _charNow = alpha_array[i];
var __charNow = _charNow;
var __charNow = new _alpha(_charNow, "[]") // "[]" should be replaced with the _charNow corresponding property from morseDic
_charObjArray.push(__charNow)
}
console.log(_charObjArray);
In _alpha, instead of:
this.dd_array = dd_array;
...you use _char to index into the morseDic object:
this.dd_array = morseDic[_char];
...and then don't pass a second argument to _alpha at all.
But if you want to pass it to _alpha as an argument:
var __charNow = new _alpha(_charNow, morseDic[_charNow]);
In JavaScript, you can access object properties either with dot notation and a property name literal (obj.foo, or morseDic.a), or using brackets notation and a property name string* (obj["foo"] or morseDic["a"]). In the latter case, the string can be the result of any expression, including a variable lookup.
* In ES6, it'll be strings or Symbols.

Categories