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]
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);
There is object destructuring:
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
and even assigning to new variable names
var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true
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]];
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 "heigth" and assign value
console.log(obj.height); // 2
Second, instead of the dot-notation you can use array index
notation using the property name as the index:
let ojb = {};
obj['height'] = 2;
console.log(obj['height']); // 2
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]; }
});
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];
// ...
}
it creates an objects with two methods: “min” and “max” and then
accesses the one that is given in the argument. If “minOrMax” is
“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"
and you can index strings:
const s = "ABC";
s[1]; // "B"
“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
}
a block might be a for-loop.
Variables declared using let are not visible outside the block and
are not “known” before declared:
function f() {
console.log(v); // Reference error
{ let v = 3; }
console.log(v); // Reference error
}
Third, you might not redeclare a variable using let:
var a = 0;
var a = 1; // OK
let b = 0;
let b = 1; // not OK
So basically, “let” is a sane way to declare variables.