DEV Community

Erik Pischel
Erik Pischel

Posted on • Originally published at on-sw-integration.epischel.de on

5 things I learnt during my latest Javascript Code Kata

Sometimes I do a code kata at codewars.com. That is a fun way to solve computer science related problems, learn on the way to solve them and especially learn from the solutions of others.

Today I completed the kata “Make a spanning tree” using Javascript. I occasionally use Javascript to write an event handler or so but I don’t have much experience in “modern” Javascript. Here is what I learnt from looking at the solutions of others.

Destructuring

I know this from my Scala class and Clojure.

You can assign array elements to variables:

var a, b, rest; 
[a, b] = [10, 20];
console.log(a); // expected output: 10 
console.log(b); // expected output: 20 
[a, b, ...rest] = [10, 20, 30, 40, 50]; 
console.log(rest); 
// expected output: [30,40,50]
Enter fullscreen mode Exit fullscreen mode

so “…rest” is assign the rest of the array.

This is nice syntactic sugar also when working with nested arrays. Eg when “edges” is an array of pairs:

// sort edges by weight
edges.sort(([edge_a, a], [edge_b, b]) => a - b);
Enter fullscreen mode Exit fullscreen mode

There is object destructuring:

var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
Enter fullscreen mode Exit fullscreen mode

and even assigning properties to new variables

var o = {p: 42, q: true};
var {p: foo, q: bar} = o; 
console.log(foo); // 42 
console.log(bar); // true
Enter fullscreen mode Exit fullscreen mode

See MDN web docs for more.

Spread operator to create an array using an array literal

Using an array literal to create an array from two other arrays:

const sets = {}; 
//... 
// new array with sets[a] elements and sets[b] elements 
const set = [...sets[a], ...sets[b]];
Enter fullscreen mode Exit fullscreen mode

Objects are associative arrays (aka maps)

Although I already knew this, kind of, this refreshes my JS knowledge.

First, you can add properties to Objects without declaring them in the first place:

let obj = {}; // anonymous object 
obj.height=2; // create new property "height" and assign value 
console.log(obj.height); // 2
Enter fullscreen mode Exit fullscreen mode

Second, instead of the dot-notation you can use array index notation using the property name as the index:

let obj = {}; 
obj['height'] = 2; 
console.log(obj['height']); // 2
Enter fullscreen mode Exit fullscreen mode

One solution uses this in order to save the weighted edges in an object just like i did in the proper Map object:

let set = {}; 
edges.filter(e => e[0][1] !== e[0][0]).forEach(e => { if (!set[e[0]] || minOrMaxFunc(set[e[0]], e[1])>00) { set[e[0]] = e[1]; } });
Enter fullscreen mode Exit fullscreen mode

Third, methods are kind of properties, too. In the same solution, “minOrMaxFunc” is cleverly choosen (“minOrMax” argument is either “min” or “max”):

function makeSpanningTree(edges, minOrMax) { 
  let minOrMaxFunc = { min: (a, b) => a - b, max: (a, b) => b - a }[minOrMax]; 
  // ... 
}
Enter fullscreen mode Exit fullscreen mode

it creates an objects with two methods: “min” and “max” and then references the one that is given in the argument. If “minOrMax=min”, a reference of the “min” method is returned.

Strings are arrays

Destructuring works with strings:

let [a,b] = 'ABC'; 
console.log(a); // "A" 
console.log(b); // "B"
Enter fullscreen mode Exit fullscreen mode

and you can index strings:

const s = "ABC"; 
s[1]; // "B"
Enter fullscreen mode Exit fullscreen mode

“var” vs. “let”

Of course, the solutions written in “modern” JS use “let” and “const” all over the place. I just reassured myself about the difference between let and var:

First, variables declared in a block using “var” are visible outside that block and are “known” before being declared:

function f() { 
  console.log(v); // undefined 
  { var v = 3; } 
  console.log(v); // 3 
}
Enter fullscreen mode Exit fullscreen mode

a block might be a for-loop.

Variables declared using let are not visible outside the block and are not “known” before they are declared:

function f() { 
  console.log(v); // Reference error 
  { let v = 3; } 
  console.log(v); // Reference error }
Enter fullscreen mode Exit fullscreen mode

Third, you might not redeclare a variable using let:

var a = 0; 
var a = 1; // OK 
let b = 0; 
let b = 1; // not OK
Enter fullscreen mode Exit fullscreen mode

So basically, “let” is a sane way to declare variables.

Top comments (11)

Collapse
 
ingusmat profile image
Ingus Mat Burleson

Don't forget that while you can't redeclare variables using let, you can reassign them.

let a = 42;
console.log(a); // 42
let a = 24; // SyntaxError: redeclaration of let a
a = 24;
console.log(a) // 24

If you want a var that can not be reassigned, use const instead of let.

const c = 43;
console.log(c) // 43
c = 51; // TypeError: invalid assignment to const `c'
Collapse
 
vshyrokov profile image
Viktor Shyrokov • Edited

Just interesting, we have such example

let set = {};
edges.filter(e => e[0][1] !== e[0][0]).forEach(e => { if (!set[e[0]] || minOrMaxFunc(set[e[0]], e[1])>00) { set[e[0]] = e[1]; } });

let's say all the records match filter, in this case we will loop through all the edges twice?

Maybe using filter with forEach not the best example, what do you think about that?

Collapse
 
erikpischel profile image
Erik Pischel

Why do you think it will loop twice?

Context: input in this case is a weighted graph like this [["AB", 4], ["BC", 8], ["AC", 5]]. A, B, C are nodes, numbers are weights.

It is just a way to initialize a data structure. filter is used just to avoid "saving" edges like ["AA", 8] in object "set".

Collapse
 
vshyrokov profile image
Viktor Shyrokov

It could loop twice, let's say we have 1 billion of records.

All that records, as example has prop like, isFilterable = true

let's say we have a filter

edges.filter(e => e.isFilterable).forEach(e => { // some logic });

in this case we will loop through all the data twice.

It would be easier to use such a condition in the foreEach directly.

In this case you'll avoid duplicate actions on data.

Yes, filter pretty cool thing, but not in this case where we have filter().foreach()

Thread Thread
 
erikpischel profile image
Erik Pischel

Now I see your point. The advantage I see in this case is that a seperate "filter" step represents a seperate step in the algorithm. Like "step 1: filter out all edges that connect only one node. step 2: ...". If you use the filter condition in the forEach directly it gets more entangled with the next step.

Thanks for your comment.

Collapse
 
severo profile image
Sylvain Lesage

I really don't understand this part of code. Is something missing?

// sort edges by weight (min/max)
const asc = t === "min";
edges.sort(([edge_a, a], [edge_b, b]) => asc ? a - b : b - a);
Collapse
 
erikpischel profile image
Erik Pischel

Well, "t" is either "min" or "max". And edges is an array of 2 element arrays, e.g.

edge=[["AB",3], ["BC",9], ["AC",5]]

sort takes a function of two parameters that returns a number indicating whether the first parameter is smaller or bigger than the second parameter. The parameters are elements of the array. In our case these are 2 element arrays. In the code example, these are destructured as edge_a (e.g. "AB") and a (e.g. 3) respectively edge_b and b. The array edges is being sorted by the second element of the 2 element arrays.
Hope this helps.

Collapse
 
severo profile image
Sylvain Lesage • Edited

Ah OK. I didn't understand that t was a variable previously set to "min" or "max". Maybe it would be clearer to precise it, o add a line of code to show it.

Thanks for your article, btw.

Thread Thread
 
erikpischel profile image
Erik Pischel

I deleted the const because it doesn't contribute to the point I want to make. It's much clearer now. Thanks for your comment.

Collapse
 
acthp profile image
acthp

extra [] on this example:

let [[a,b]] = 'ABC';

should be just

let [a,b] = 'ABC';

Collapse
 
erikpischel profile image
Erik Pischel

Fixed, thanks. Was working with nested arrays in this Kara so I got used to [[a,b]] :-)