NAV Navbar
go javascript

1. Basics

Basic language syntax, such as assignment, control structures, function defintion etc.

Assignment, Variable bindings

var x int // declare
x = 3 // assignment
y := 4 // := indicates type inference

a, b := func1() // multiple assignments

var x int // declare
x = 3 // assignment
y := 4 // := indicates type inference
var a = 42;
let x = 123;
const y = 'abc';
feature \ lang Go JS
Declare Variable var var, let
Declare Constant const const
binding / assignment = =
binding w/ type infer := NA

Define functions

// no param, no return
func foo() {
  fmt.Println("hello world")
}

// with param and return
func sum(a, b int) int {
   return a + b
}

// return multiple restuls
func sumAndProduct(a, b int) (int, int) {
  return a + b, a * b
}

// no param, no return
function foo() {
  console.log("hello world");
}

// with param and return
function sum(a, b) {
  return a + b;
}

// return multiple results
function sumAndProduct(a, b) {
  // or return { sum: a + b, product: a * b }
  return [a + b, a * b];
}

// arrow function
const sum = (a, b) => a + b;
feature \ lang Go JS
denote function definition func function
denote arrow function defintion NA =>

Built-in Data types

string and char

var s1 string = "Hello"
var s2 string = `string goes to
the next line`

// string interpolation
import ("fmt")
date := fmt.Sprintf("%d-%d-%d", year, month, day)

var c1 rune = '我' //rune is alias for int32, which hold a unicode for the character

const s1 = "hello";
const s2 = 'world';
const s3 =`hello
world`;

// string interpolation
const s4 = `hello ${s2}`;
feature \ lang Go JS
with quote Yes Yes
with single-quote Yes Yes
multiline string Yes, with backtick Yes, with backtick
string interpolation No, via fmt Yes

numbers

Go's integer types are:

Go's float types are: float32 and float64

var u uint = 42

var f float64 = 3.1415826525
var pi float32 = 22. / 7

// > `unit` is either 32 or 64 bit.
// > `int` isn't alias to int32. `int` could be 32bit or 64bit.
// > `uintptr` is an unsigned integer large enough to store the uninterpreted bits.
// > `byte` is alias for `uint8`.
// > `rune` is alias for `int32`.
const i = 123;
const f = 123.123;
feature \ lang Go JS
integer types uint8, uint16, uint32, uint64
int8, int16, int32, int64
"integer" via Number type
float types float32, float64 float via Number type

boolean types

var f bool = false
var t bool = true
const f = false;
const t = true;
feature \ lang Go JS
Truthy true true, others values not listed below
Falsy false false, 0, -0, 0n, "", null, undefined, NaN

Collections/Arrays

var xs [5]int = [5]int{1, 2, 3, 4, 5}
xs := [5]int{1, 2, 3, 4, 5} // or [...]int{1, 2, 3, 4, 5}

var twoD [2][3]int
for i := 0; i < 2; i++ {
    for j := 0; j < 3; j++ {
        twoD[i][j] = i + j
    }
}
fmt.Println("2d: ", twoD)

// copy/clone array
ys := xs
// reference original array
zs := &xs
var cars = ["apple", "organce", "pear"];
var cars = new Array("Saab", "Volvo", "BMW");
for (let i = 0; i < 3; i ++ ) {
  console.log(cars[i]);
}

// copy/clone array
const newCars = cars.slice();
const newCars1 = [...cars];

// reference original array
const carsRef = cars;
feature \ lang Go JS
Define & Initialization var xs [5]int = [5]int{} var xs = []
Subscript xs[i] xs[i]
Size of Array len(xs) xs.length
Copy Array ys := xs ys = xs.slice() or ys = [...xs]

Collections/List(or List-like structure)

// slice literal
letters := []string{"a", "b", "c", "d"}

// using function make
// func make([]T, len, cap) []T
s := make([]byte, 5, 5)

// create from any array
x := [3]string{"hello", "world"}
s := x[:] // a slice referencing to the storage of x

// sub-slice
b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
// b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b

// append
s := []string{"a", "b", "c"}
s = append(s, "d")
s = append(s, "e", "f")

// copy
c := make([]string, len(s))
copy(c, s)

// remove
r := []string{"a", "x", "b", "c"} 
r1 := append(r[:1], r[2:]...) 
// r  => [a b c c] // side effects
// r1 => [a b c]


const xs = ['a', 'b', 'c'];
// sub array/list
xs.slice(0, 2); // => ['a', 'b']
// append
xs.push('d'); // => ['a', 'b', 'c', 'd'];
// pop
xs.pop(); // => 'd', xs becomes ['a', 'b', 'c']
// copy
xs.slice(); // => ['a', 'b', 'c']
// remove 'b'
xs.splice(1, 1); // 'b', xs == ['a', 'c']

In Golang, Slice is usually used instead of List, due to it's first-class suppport in syntax and performance advantage.

feature \ lang Go JS
Define & Initialization int{} or make([]int, 5, 5) const xs = ['a', 'b', 'c']
append append(xs, "e", "f") xs.push('e')
Pop xs[:len(xs) -1] xs.pop()
sub-list xs[a:b] xs.slice(a,b)
copy copy(target, source) xs.slice()
remove via append via splice

Collections/Maps

// create empty map
m := make(map[string]int)

// create with initial values
m: = map[string]int{"foo": 1, "bar": 2}

// put value
m["k1"] = 49
m["k2"] = 81

// get value
m["k1"] //=> 49

// delete k-v
delelte(m, "k2")

// iterate
for k, v := range m {
  // do something with k and v
}

// create empty map
let m = new Map();

// create with initial values
let m = new Map([["foo", 1], ["bar", 2]]);

// put value
m.set("k1", 1);

// get value
m.get("k1");

// delete k-v
m.delete("k1");

// iterate
for (let [k, v] of m.entries()) {
  // do something with k and v
}

feature \ lang Go JS
Define make(map[string]int) new Map()
Initialization map[string]int{"foo": 1, "bar": 2} new Map([["foo", 1], ["bar", 2]])

Collections/Iterator(or Range)

// iterate over an array
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
    sum += num
}

// iterate over an map
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
    fmt.Printf("%s -> %s\n", k, v)
}
// iterate over an array
const array1 = ['a', 'b', 'c'];
for (const element of array1) {
  console.log(element);
}

// iterate over an Map
const myMap = new Map();
myMap.set("0", "foo");
myMap.set("1", "bar");
myMap.set("2", "baz");

for (const [key, value] of myMap.entries()) {
  console.log(`${key} -> ${value}`);
}

// iterate over an object - method 1
for (const [key, value] of Object.entries(obj)) {
  console.log(`${key} -> ${value}`);
}

// iterate over an object - method 2
for (const k in obj) {
  console.log(`${k} -> ${obj[k]}`);
}

feature \ lang Go JS
Syntax for i, value := range iterable {} for (const value of iterable) {}

Conditional/If-Else

// simple
if 7 % 2 == 0 {
  fmt.Println("7 is even")
} else {
  fmt.Println("7 is odd")
}

// if with preceding statement
if num := 9; num < 0 {
    fmt.Println(num, "is negative")
} else if num < 10 {
    fmt.Println(num, "has 1 digit")
} else {
    fmt.Println(num, "has multiple digits")
}
let x = 7;
if (x % 2 === 0 ) {
  console.log(`${x} is even`);
} else {
  console.log(`${x} is odd`);
}

feature \ lang Go JS
Keywords if, else if, else

Conditional/Switch


// simple
i := 2
fmt.Print("Write ", i, " as ")
switch i {
case 1:
  fmt.Println("one")
case 2:
  fmt.Println("two")
case 3:
  fmt.Println("three")
}

// multiple match in one branch
switch time.Now().Weekday() {
case time.Saturday, time.Sunday: 
  fmt.Println("It's the weekend")
default: 
  fmt.Println("It's a weekday")
}

// switch without expression
t := time.Now()
switch {
  case t.Hour() < 12:
    fmt.Println("It's before noon")
  default: 
    fmt.Println("It's after noon")
}

// check value type
whatAmI := func(i interface{}) {
  switch t := i.(type) {
  case bool:
    fmt.Println("I'm a bool")
  case int:
    fmt.Println("I'm an int")
  default:
    fmt.Printf("Don't know type %T\n", t)
  }
}
whatAmI(true)
whatAmI(1)
whatAmI("hey")

const expr = 'Papayas';
switch (expr) {
  case 'Oranges':
    console.log('Oranges are $0.59 a pound.');
    break;
  case 'Mangoes':
  case 'Papayas':
    console.log('Mangoes and papayas are $2.79 a pound.');
    // expected output: "Mangoes and papayas are $2.79 a pound."
    break;
  default:
    console.log(`Sorry, we are out of ${expr}.`);
}

feature \ lang Go JS
Keywords switch, case, default switch, case, default, break

Loops/for

// classic for loop
for j := 0; j < 10; j++ {
  fmt.Println(j)
}
let str = '';
for (let i = 0; i < 9; i++) {
  str = str + i;
}
console.log(str);
feature \ lang Go JS
Keywords for for

Loops/while

// while loop equivalent
i := 1
for i <=3 {
  fmt.Println(i)
  i = i + 1
}

// while-true loop, looping until break
for {
  fmt.Prinlnt("loop")
  break
}
let n = 0;

while (n < 3) {
  n++;
}
feature \ lang Go JS
Keywords for while

2. Intermediate

Pointers / References / Pass-by-X

func zeroval(ival int) {
    ival = 0
}

func zeroptr(iptr *int) {
    *iptr = 0
}

func main() {
    i := 1
    fmt.Println("initial:", i)

    zeroval(i)
    fmt.Println("zeroval:", i)
    zeroptr(&i)
    fmt.Println("zeroptr:", i)

    fmt.Println("pointer:", &i)

}
function changeStuff(a, b, c)
{
  a = a * 10;
  b.item = "changed";
  c = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};

changeStuff(num, obj1, obj2);

console.log(num); // => 10
console.log(obj1.item); // => changed
console.log(obj2.item); // => unchanged

From programmer's perspective, we can always think it's passing value for both golang and javascript.

For golang, it's either passing a normal value (a copy of the orginal vlaue), or passing a reference value. For a reference value, dereference (*) is required to access the value.

For javascript, it's the same. However there are two differences as compared to golang: - programmer doesn't have control to passing a normal value or a reference value. - dereference happens implicitly (with .).

Class / Struct

// define struct
type person struct {
  name string
  age  int
}

// instantiate
p1 := person{name: "Alice", age: 30}
p2 := &person{name: "Bob", age: 29}

// change prop's value
p1.age = 40
(*p2).age = 39 // or p2.age = 39 (where auto deferencing happens)

// print objects
fmt.Println(p1) // => {Alice 40}
fmt.Println(p2) // => &{Bob 39}
// define pre-ES6
function Person(name, age) {
  this.name = name;
  this.age = age;
}
// since ES6
class PersonES6 {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

// instantiate
const p1 = new Person("Alice", 30);
const p2 = new PersonES6("Bob", 29);

// change prop's value
p1.age = 40;
p2.age = 39;

// print objects
console.log(p1); // => Person { name: 'Alice', age: 40 }
console.log(p2); // => PersonES6 { name: 'Bob', age: 39 }
feature \ lang Go JS
keyword struct, type class

Objects

type person struct {
  name string
  age  int
}

p1 := person{name: "Alice", age: 30} // struct literal
var p2 *person = new(person)         // with new keyword, it returns a pointer
p2.name = "Bob"
p2.age = 29

// print objects
fmt.Println(p1) // => {Alice 30}
fmt.Println(p2) // => &{Bob 29}
class PersonES6 {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

const p1 = new PersonES6("Alice", 30);
const p2 = {name: "Bob", age: 29}; // object literal, similar to strut literal

console.log(p1); // PersonES6 { name: 'Alice', age: 30 }
console.log(p2); // => { name: 'Bob', age: 29 }
feature \ lang Go JS
keyword new new
support literal yes yes

Methods

type rect struct {
    width, height int
}
func (r *rect) area() int {
    return r.width * r.height
}
r := &rect{width: 2, height: 4}
var area int = r.area()
fmt.Println(area) // => 8
const r1 = {
  width: 2,
  height: 4,
  area: function() {
    return this.width * this.height;
  }
}
console.log(r1.area());
// or 
class Rect {
    constructor(width, height) {
    this.width = width;
    this.height = height;
  }
  area() {
    return this.width * this.height;
  }
}
console.log(new Rect(2, 4).area())

Javascript's way of attaching function to object/class is quite traditional.

Golang's way is sort of "de-coupled".

Interface

type geometry interface {
    area() float64
    perim() float64
}

type rect struct {
    width, height float64
}

func (r rect) area() float64 {
    return r.width * r.height
}

func (r rect) perim() float64 {
    return 2*r.width + 2*r.height
}

func measure(g geometry) {
    fmt.Printf("Geometry %#v, area=%f, perimeter=%f \n", g, g.area(), g.perim())
}

r := rect{width: 3, height: 4}
measure(r) // => Geometry main.rect{width:3, height:4}, area=12.000000, perimeter=14.000000 
// NA

In go, this is no implements keyword for implement an interface. If type TA defines all methods specified in interface IA, it is said that type TA satifies interface IA.

Enumeration

import (
    "errors"
    "fmt"
)

type Season string

const (
    SUMMER Season = "summer"
    WINTER        = "winter"
    SPRING        = "spring"
    AUTUMN        = "autumn"
)

//alternative
const (  // iota is reset to 0
  c0 = iota  // c0 == 0
  c1 = iota  // c1 == 1
  c2 = iota  // c2 == 2
)

func monthToSeason(month int) (Season, error) {
    var season Season
    switch month {
    case 9, 10, 11:
        season = SPRING
    case 12, 1, 2:
        season = SUMMER
    case 3, 4, 5:
        season = AUTUMN
    case 6, 7, 8:
        season = WINTER
    default:
        return "", errors.New("Invalid month")
    }
    return season, nil
}

func main() {
    month := 8
    season1, err := monthToSeason(month)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Month %d belongs to %s\n", month, season1)
}
const seasons = {
    SUMMER: 'summer',
    WINTER: 'winter',
    SPRING: 'spring',
    AUTUMN: 'autumn'
}

switch(season){
    case seasons.SUMMER:
    // Do something for summer
    case seasons.WINTER:
    //Do something for winter
    case seasons.SPRING:
    //Do something for spring
    case seasons.AUTUMN:
    //Do something for autumn
}

Neither go or javascript has built-in support to enumeration. However, we can use some tricks to simulate it.

References

Error handling

func f1(arg int) (int, error) {
    if arg == 42 {
        return -1, errors.New("can't work with 42")
    }
    return arg + 3, nil
}

// custom error, implement Error() method
func (e *CustomError) Error() string {
    return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
func f2(arg int) (int, error) {
    if arg == 42 {
        return -1, &CustomError{arg, "can't work with it"}
    }
    return arg + 3, nil
}
try {
  throw new Error('Whoops!')
} catch (e) {
  console.error(e.name + ': ' + e.message)
}

// custom error
class CustomError extends Error {
  constructor(foo = 'bar', ...params) {
    // Pass remaining arguments (including vendor specific ones) to parent constructor
    super(...params)

    // Maintains proper stack trace for where our error was thrown (only available on V8)
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, CustomError)
    }

    this.name = 'CustomError'
    // Custom debugging information
    this.foo = foo
    this.date = new Date()
  }
}

Basic Concurrency

// defining two expensive computations
func compute1() string {
  // expensive computing
  time.Sleep(time.Second)
  return "3.14"
}
func compute2() string {
  // expensive computing
  time.Sleep(time.Second * 2)
  return "42"
}

//fire and forget, non-blocking
go func(){ r := compute1(); fmt.Println(r) }()

// wait for one result
r := make(chan string, 1)
go func() { r <- compute1() }()
fmt.Println(<-r) // => '3.14'

// wait for two results
r1 := make(chan string, 1)
r2 := make(chan string, 1)
go func() { r1 <- compute1() }()
go func() { r2 <- compute2() }()
fmt.Println(<-r1) // => 3.14
fmt.Println(<-r2) // => 42

// wait for first resolved
c1 := make(chan string)
c2 := make(chan string)
go func() { c1 <- compute1() }()
go func() { c2 <- compute2() }()
select {
case msg1 := <-c1:
    fmt.Println("received", msg1) 
case msg2 := <-c2:
    fmt.Println("received", msg2)
}
// => "received 3.14"
async function fetchRemote1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('3.14...');
    }, 1000);
  });
}
async function fetchRemote2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('42');
    }, 2000);
  });
}
// fire and forget, non-blocking
fetchRemote1().then(console.log).catch(console.err)

// wait for one result
const pi = await fetchRemote1(); // => '42'

// wait for multiple results
const [pi, life] = await Promise.all([fetchRemote1(), fetchRemote2()]) // => ['3.14...', '42']

// wait for first resolved
const winner = await Promise.race([fetchRemote1(), fetchRemote2()]) // => '3.14...'

Golang goroutines are very lightweight, as well as JS Promises.

Golang is a bit verbose as compared to JS.

IO, file read/write

// dealing with small files
func rw_small_file() {
    // read the whole file at once
    b, err := ioutil.ReadFile("input.txt")
    if err != nil {
        panic(err)
    }

    // write the whole body at once
    err = ioutil.WriteFile("output.txt", b, 0644)
    if err != nil {
        panic(err)
    }
}

// dealing with big file
func rw_big_file() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := fi.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := fo.Write(buf[:n]); err != nil {
            panic(err)
        }
    }
}

// read the entire file
const contents = require('fs').readFileSync('filename', 'utf8');
console.log(contents);

// write to file
require('fs').writeFileSync("./tmp.txt", "Hey there!"); 

// read big file
const stream = require("fs").createReadStream("./bigfile.txt");
stream.on("data", function(data) {
    var chunk = data.toString();
    console.log(chunk);
}); 

// write to big file
const stream = require("fs").createWriteStream("tmp.txt", { flags:'a' });
stream.write("Tutorial on Node.js")
stream.write("Introduction")

Golang has very traditional style of dealing with files, which resulting clear but verbose coding.

Javascript(Nodejs)'s API is much more concise. Also NodeJS provides both sync and async style APIs.

Http Server

import (
    "fmt"
    "net/http"
)

func hello(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "hello\n")
}

func main() {
    http.HandleFunc("/hello", hello)
    http.ListenAndServe(":8090", nil)
}
const http = require('http')

const hello = (request, response) => {
  console.log(request.url);
  response.end('hello\n');
}

const server = http.createServer(hello);

server.listen(8090, (err) => {
  if (err) {
    return console.error('something bad happened', err)
  }
});

Both golang and Nodejs provide easy-to-use API to create a basic http server.

Http Client

import (
    "bufio"
    "fmt"
    "net/http"
)

func main() {

    resp, err := http.Get("http://localhost:8090/hello")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println("Response status:", resp.Status)

    scanner := bufio.NewScanner(resp.Body)
    for i := 0; scanner.Scan() && i < 5; i++ {
        fmt.Println(scanner.Text())
    }

    if err := scanner.Err(); err != nil {
        panic(err)
    }
}
// using axios
const axios = require('axios');
try {
  const res = await axios({
    method: 'POST',
    url: 'https://localhost:3000',
    headers: {
      client_id: 'client123',
      Authorization: 'Bearer token123'
    },
    data: {
      field1: 123,
      field2: 'abc'
    }
  });
  console.log(res.data); // 2xx
} catch (err) {
  console.error(err); // non-2xx
}

Consider timeout cases in case of prolonged server response.

JSON deserialize/serialize

import ("encoding/json" "fmt"   "log" "time")
// deserialize

type FruitBasket struct {
    Name    string
    Fruit   []string
}

func deserialize() {
    jsonData := []byte(`{
        "Name":"Standard",
        "Fruit":["Apple","Banana","Orange"]
    }`)
    var basket FruitBasket
    err := json.Unmarshal(jsonData, &basket)
    fmt.Printf("%+v\n", basket)
}

func serialize() {
    jsonData, err := json.Marshal(FruitBasket{
        Name:    "Standard",
        Fruit:   []string{"Apple", "Banana", "Orange"}
    })
    fmt.Println(string(jsonData))
}
// deserialize
JSON.parse('{"key1": 123, "key2": "abc"}') // => { key1: 123, key2: 'abc' }

// serialize
JSON.stringify({ key1: 123, key2: 'abc' }) // => '{"key1":123,"key2":"abc"}'

Javascript, is almost the easiest language in dealing with JSON.

Golang Like other static typed language, requires defined types to match JSON message.

DateTime

import "time"
// get timestamp in milliseconds
time.Now().UnixNano() / 1000000 // => 1596239578956

// create date time object from timestamp
time.Unix(0, 1596239578956 * int64(time.Millisecond)) // => 2020-07-31 23:52:58.956 +0000 UTC
time.Unix(1596239578, 0) // => seconds, 2020-07-31 23:52:58 +0000 UTC

// read/write ISO format without timezone information
// need to manually assign timezone to match RFC3339 
dt, _ := time.Parse(time.RFC3339, "2012-07-29T11:05:45" + "+00:00")// => 2012-07-29 11:05:45 +0000 UTC

// read/write ISO format with timezone information
dt, _ := time.Parse(time.RFC3339, "2012-03-29T10:05:45+10:00") // => 2012-03-29 10:05:45 +1000 +1000
dt, _ := time.Parse(time.RFC3339, "2012-03-29T10:05:45+08:00") // => 2012-03-29 10:05:45 +0800 +0800

// print local DateTime String, with specified timezone
tz1, _ := time.LoadLocation("Australia/Sydney")
tz2, _ := time.LoadLocation("Australia/Perth")
time.Unix(1596239578, 0).In(tz1).Format(time.RFC3339) // => '2020-08-01T09:52:58+10:00'

// read/write customized format
time.Unix(1596239578, 0).In(tz2).Format("2006-01-02 15:04:05") // => 2020-08-01 07:52:58
t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2020-08-01 07:52:58", tz2)
t // => 2020-08-01 07:52:58 +0800 AWST
t.In(tz1) // => 2020-08-01 09:52:58 +1000 AEST
// get timestamp in milliseconds
new Date().getTime() // current timestamp: 1596147462418

// create date time object from timestamp
new Date(1596147462418) // => 2020-07-30T22:17:42.418Z

// read/write ISO format without timezone information
new Date('2012-07-29T11:05:45') // => 2012-07-29T01:05:45.000Z, printed UTC value, local timezone is used during parsing

// read/write ISO format with timezone information
new Date('2012-03-29T10:05:45+10:00') // => 2012-03-29T00:05:45.000Z, printed UTC value
new Date('2012-03-29T10:05:45+08:00') // => 2012-03-29T02:05:45.000Z

// print local DateTime String, with specified timezone
const moment = require('moment-timezone');
moment(new Date('2012-03-29T10:05:45+08:00')).format(); // => '2012-03-29T13:05:45+11:00'
moment(new Date('2012-03-29T10:05:45+08:00')).tz('UTC').format(); // => '2012-03-29T02:05:45Z'

moment(new Date('2012-03-29T10:05:45+08:00')).tz('Australia/Perth').format(); // => '2012-03-29T10:05:45+08:00'

// read/write customized format
moment.tz("2012-03-29 13:05:45", "YYYY-MM-DD hh:mm:ss", "Australia/Perth").toDate(); // => 2012-03-29T05:05:45.000Z

moment("2012-03-29 13:05:45+11:00").format('YYYY-MM-DD hh:mm:ss') // => '2012-03-29 01:05:45'

moment("2012-03-29 13:05:45+11:00").tz('Australia/Perth').format('YYYY-MM-DD hh:mm:ss') // => '2012-03-29 10:05:45'

Javascript Date provides very basic utilites for DateTime. Hence, for complex parsing and formatting, devs usually use moment and moment-timezone.

Golang has quite sufficient built-in utilities from package time.

Access RDBMS (Postgres)

Golang has database/sql, which provide a generic interface around SQL databases. It is similar to Java's JDBC.

NodeJS doesn't have standard interface to access SQL databases. However, the style varies from one driver to another. Often both callback- and promise-based APIs are provided.

Packages or Modules

In golang, a publishable unit is called module, consisting a list of packages. A package can be one file or many files. This is similar to Java.

In javascript, a publishable is called package, consisting a list of modules. A module is one JS file.

Useful commands

Dependency Management

Project Structure

3. Advanced

Garbage collection & Memory leaks

Memory model

Concurrency

4. Further

Language Caveats

New features

Interact with other languages

Frontend - WebAssembly

Trend in other areas other than backend