JavaScript// hello.js — run: node hello.js
console.log("Hello, world");
// any file can be the entry point,
// and top-level code just runs
→
Go// hello.go — run: go run hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, world")
}
Every Go file belongs to a package. Only package main with a func main() builds into a runnable program. There is no top-level code — statements live inside functions.
JavaScriptlet count = 1;
count = 2;
const name = "ada";
let empty; // undefined
var old = true; // avoid
→
Gocount := 1 // inside a function
count = 2
const name = "ada"
var empty string // "" — the zero value
var n int // 0
var ok bool // false
:= declares and infers the type in one step, but only inside a function; at package level use var. There is no undefined — every variable starts at its type's zero value. A declared local you never read is a compile error, not a warning.
JavaScripttypeof 42; // "number"
Number("42"); // 42
String(42); // "42"
parseInt("42", 10); // 42
(42).toFixed(2); // "42.00"
1 / 2; // 0.5
→
Goreflect.TypeOf(42) // int
n, err := strconv.Atoi("42")
s := strconv.Itoa(42)
f, err := strconv.ParseFloat("4.2", 64)
fmt.Sprintf("%.2f", 42.0) // "42.00"
1 / 2 // 0 — integer division
float64(1) / 2 // 0.5
One number becomes int, int64, float64 and friends. Conversion is always explicit — float64(i), int(f) — and never happens behind your back, so mixing an int and a float64 in one expression will not compile. int(2.9) truncates to 2. Parsing returns a value and an error.
JavaScript1 == "1"; // true
1 === "1"; // false
if (list.length) {}
if (str) {}
if (!user) {}
value ?? fallback
user?.address?.city
→
Go// == is always strict.
// comparing different types won't compile.
if len(list) > 0 { }
if str != "" { }
if user == nil { }
// no ?? and no ?. — check it
if v, ok := m[k]; ok { use(v) }
if u != nil && u.Address != nil { }
There is no truthiness: if takes a bool and nothing else, so every check is spelled out. Structs and arrays compare with == field by field; slices, maps and functions can only be compared against nil, and reflect.DeepEqual or slices.Equal handles the rest.
JavaScriptif (x > 1) {} else if (y) {} else {}
for (let i = 0; i < 10; i++) {}
while (ok) {}
do {} while (ok);
for (const x of xs) {}
for (const k in obj) {}
const size = x > 1 ? "big" : "small";
→
Goif x > 1 { } else if y { } else { }
if v, err := f(); err != nil { } // scoped init
for i := 0; i < 10; i++ { }
for ok { } // while
for { break } // infinite
for i, x := range xs { }
for k, v := range m { }
// no ternary — write the if
for is the only loop keyword and covers all four shapes. Conditions take no parentheses, braces are never optional, and the opening brace must sit on the same line. The scoped init form — if v, err := f(); err != nil — keeps v and err from leaking into the surrounding scope.
JavaScriptswitch (x) {
case 1:
one();
break;
case 2:
case 3:
few();
break;
default:
other();
}
→
Goswitch x {
case 1:
one()
case 2, 3:
few()
default:
other()
}
switch { // no subject:
case x > 10: // an if/else chain
big()
}
Cases break on their own; falling through is opt-in with the fallthrough keyword. One case can list several values, a case can carry an init statement, and a subjectless switch is the idiomatic replacement for a long if/else ladder.
JavaScriptfunction counter() {
let n = 0;
return () => ++n;
}
const next = counter();
next(); // 1
next(); // 2
for (var i = 0; i < 3; i++)
setTimeout(() => log(i)); // 3 3 3
for (let i = 0; i < 3; i++)
setTimeout(() => log(i)); // 0 1 2
→
Gofunc counter() func() int {
n := 0
return func() int { n++; return n }
}
next := counter()
next() // 1
next() // 2
for i := 0; i < 3; i++ {
go func() { fmt.Println(i) }()
}
// 0 1 2 (in some order) — since Go 1.22
// each iteration gets a fresh i, like let
Closures work exactly as you expect: they capture variables, not values. Since Go 1.22 every loop iteration gets its own copy of the loop variable, matching let. In older code you will still see i := i inside the loop body or func(i int) passed as an argument — that is the pre-1.22 fix for the var-style sharing bug.