Python vs JavaScript — First, Where Do They Fit?
Before any JavaScript syntax at all: a map of the programming-language landscape, so Python and JavaScript's similarities and differences have context instead of feeling like an arbitrary pile of rules.
1. The 10-Minute Map of Programming Languages
"Programming language" is an enormous category. Before zooming into Python and JavaScript, it helps to see roughly where they sit among languages you may have heard of — not as a strict family tree, but as a rough map.
This is a mental map, not an evolutionary tree or a strict hierarchy. Arrows and boxes here mean "loosely near," not "descended from" or "better than." A language can genuinely belong near more than one cluster — Go borrows systems-language concerns while still being garbage-collected and easy to pick up; TypeScript is JavaScript with a type layer bolted on top, not a separate ecosystem.
2. Multiple Axes, Not One Ladder
A single "advanced → beginner" or "low-level → high-level" scale can't actually place these languages correctly, because they differ along several independent questions at once. A language can score differently on each one — these are axes, not boxes.
- How much abstraction does it provide from the machine?
- Static or dynamic typing?
- What happens between source code and execution?
- Native machine code, bytecode, a VM, an interpreter, JIT compilation, or some mix?
- Who manages memory — the programmer, or the runtime?
- Does it use garbage collection?
- What programming paradigms does it support?
- What environments does it normally run in?
- What was it primarily designed to make easier?
- Where is it commonly used today?
3. Language Landscape Grid
A map, not a lesson — skim once, keep coming back to it if you want, don't memorize it.
| Language | Abstraction | Typing | Execution model | Memory | Original motivation | Common today |
|---|---|---|---|---|---|---|
| Assembly | Lowest | None (raw) | Direct machine code | Manual | Direct hardware control | Firmware, drivers, tight loops |
| C | Low | Static | Compiled to native | Manual | Portable systems programming | OS kernels, embedded |
| C++ | Low–mid | Static | Compiled to native | Manual (+ RAII) | Abstraction w/o giving up control | Games, engines, perf-critical apps |
| Rust | Low–mid | Static | Compiled to native | Ownership/borrowing, no GC | Systems control, memory safety | Systems tools, WASM, infra |
| Go | Mid | Static | Compiled to native | Garbage collected | Simplicity at scale | Cloud services, CLIs |
| C# | Mid | Static (+ dynamic escape hatches) | Compiled to IL, JIT on .NET runtime | Garbage collected | Modern managed apps on .NET | Enterprise, games (Unity), web |
| Java | Mid | Static | Compiled to bytecode, JVM (often JIT) | Garbage collected | Portable managed apps ("write once") | Enterprise backends, Android (via Kotlin/Java) |
| Kotlin | Mid | Static | Compiled to JVM bytecode (or native/JS) | Garbage collected | Modern ergonomics on the JVM | Android, JVM backends |
| Swift | Mid | Static | Compiled to native | Automatic reference counting | Modern, safe Apple-platform apps | iOS/macOS apps |
| Python | High | Dynamic | Compiled to bytecode, run on a VM (CPython) | Garbage collected | Readability, productivity | Scripting, data/ML, backends |
| JavaScript | High | Dynamic | Parsed/interpreted + JIT-compiled by an engine | Garbage collected | Scripting behavior in web pages | Web front/back end, apps, tooling |
| TypeScript | High | Static (compiles away) | Compiles to JavaScript, then runs as JS | Same as JS (garbage collected) | Type-checking tooling for JS | Large JS codebases |
| Bash | High (for its domain) | Untyped (mostly strings) | Interpreted by the shell | N/A | Automating shell commands | Scripts, CI/CD glue |
| SQL | Declarative | Static, schema-driven | Query planned/executed by a database engine | N/A | Describing what data you want, not how to get it | Databases, analytics |
| HTML | Declarative | N/A (markup) | Parsed into a document tree | N/A | Describing document structure | Every web page |
| CSS | Declarative | N/A (rules) | Parsed and applied by a rendering engine | N/A | Describing presentation, separate from structure | Every web page |
Loose: "JavaScript is interpreted, Python is interpreted, C# is compiled" — as if that's three separate, mutually exclusive buckets.
More precise: a JavaScript engine (V8, SpiderMonkey, JavaScriptCore, and others) typically parses your source, may interpret it initially, and JIT-compiles hot code paths to native machine code while running — several strategies used together, not one. CPython typically compiles Python source to its own bytecode first, then that bytecode runs on the CPython virtual machine. C# compiles to an intermediate language (IL) ahead of time, which the .NET runtime then JIT-compiles. None of these are purely "compiled" or purely "interpreted" in the old, simple sense — "interpreted vs. compiled" is really several related but separate questions (row 3 and row 4 in the axes list above), not one switch.
4. Same Problem, Different Engineering Choices
Every language on this second grid solves "how do I manage memory and get useful work done" — the interesting part is how differently they each choose to do it. None of these choices is objectively "best" — each is a tradeoff suited to different problems.
| Dimension | C++ | Rust | Go | C# | Python | JavaScript |
|---|---|---|---|---|---|---|
| Typing | Static | Static | Static | Static | Dynamic | Dynamic |
| Memory | Manual + RAII | Ownership/borrowing | Garbage collected | Garbage collected | Garbage collected | Garbage collected |
| Compile/run | Compiled to native | Compiled to native | Compiled to native | Compiled to IL, JIT | Compiled to bytecode, VM | Parsed + interpreted + JIT by an engine |
| Runtime | None (thin) | None (thin) | Go runtime | .NET runtime (CLR) | CPython VM | JS engine + host (browser/Node) |
| Concurrency | Threads, manual sync | Threads, ownership-checked | Goroutines + channels | Threads, async/await, Tasks | Threads (GIL-limited), async/await | Single-threaded + event loop, async/await |
| Abstraction/control | High abstraction, still low-level control | Systems control, safety enforced by compiler | Simple, intentionally small language surface | High abstraction, managed | Very high abstraction | Very high abstraction |
| Typical strength | Performance-critical software with fine control | Performance with memory-safety guarantees | Simple, scalable network services | Productive, large managed applications | Fast to write, read, and iterate on | The only language that runs natively in every browser |
5. Just Enough History to Explain the Differences
Engineering pressures and tradeoffs, not mythology — nobody here was "invented because X was terrible."
C grew up in close relationship with operating systems and hardware — it's still the language most OS kernels are written in.
C++ added powerful abstractions (classes, templates, RAII) on top of C while keeping substantial systems-level control.
Java popularized the managed-VM approach for portable applications — compile once, run anywhere a JVM exists.
JavaScript was created to script behavior inside web pages, on a short timeline, then grew far beyond that original browser-only environment.
C# was developed as a modern managed language built around the .NET platform.
Python was optimized heavily for readability and productivity as a general-purpose scripting/programming language.
Go was designed partly in response to complexity encountered building and maintaining large-scale software systems.
Rust was designed to give systems-level control while preventing entire classes of memory-safety bugs at compile time.
TypeScript added static type analysis and tooling on top of the existing JavaScript ecosystem, without replacing it.
6. Now Zoom In: Python vs JavaScript
We now have the map. Set most of it aside for the rest of this class — the two dots we actually care about here are Python and JavaScript. Both sit in the same rough neighborhood: high-level, dynamically typed, garbage-collected, general-purpose languages. That similarity is real, and it's exactly why the specific differences below are worth slowing down for — nothing forces two languages in the same neighborhood to make the same design choices.
Variable declaration
Syntaxage = 30let age = 30;Python binds a name with plain assignment. JavaScript requires a declaration keyword (let, const, or the legacy var) — there's no bare-assignment form for a new binding.
Reassignment vs "constants"
Language semanticsMAX_SIZE = 10
# no real enforcement —
# it's just a naming conventionconst MAX_SIZE = 10;
MAX_SIZE = 20; // throws TypeErrorPython has no language-enforced constant — ALL_CAPS is a human convention only. JavaScript's const is enforced by the engine: reassigning it is a runtime error. (It only locks the binding, not the value's contents — Lab 21 covers what that means for objects.)
Dynamic typing
Type systemx = 5
x = "five" # finelet x = 5;
x = "five"; // fineBoth are dynamically typed — a variable is just a name currently pointing at a value, and that value's type can change over the variable's lifetime in either language. Lab 03 goes deep on this from the JavaScript side.
"No value" values
JavaScript-specific gotchax = Nonelet x; // undefined
let y = null; // nullPython has one deliberate "nothing" value, None. JavaScript splits this into two: undefined (the engine's own default for an unassigned variable) and null (a value you assign yourself, on purpose). Lab 04 covers this split in full, including the undeclared-name case.
Equality
JavaScript-specific gotcha1 == "1" # False1 == "1" // true
1 === "1" // falsePython's == never silently converts between types like this. JavaScript has two equality operators: == allows type coercion before comparing, === does not. This gets its own dedicated lab later in the curriculum.
Truthiness
Language semanticsif []: # falsy
if "": # falsy
if "0": # truthy (non-empty str)if ([]) {} // truthy!
if ("") {} // falsy
if ("0") {} // truthyBoth languages coerce values to true/false in a condition, but the falsy list differs: Python treats an empty list/dict/tuple as falsy; JavaScript treats every object — including an empty array [] — as truthy. Only a specific short list of primitive values is falsy in JS.
Blocks: indentation vs braces
Syntaxif age >= 18:
print("adult")if (age >= 18) {
console.log("adult");
}Python uses indentation itself to define a block. JavaScript uses { } — indentation is just a convention for humans and has no effect on how the code runs.
Functions as values
General programming conceptdef greet():
return "hi"
say_hi = greet
print(say_hi())function greet() {
return "hi";
}
let sayHi = greet;
console.log(sayHi());"Functions are first-class values" isn't unique to either language — both let you store a function in a variable and call it through that name. JavaScript leans on this even more heavily in everyday code (Lab 11 covers why).
Lists vs arrays
Ecosystem / namingitems = [1, 2, 3]
items.append(4)let items = [1, 2, 3];
items.push(4);Both are ordered, mutable, dynamically-sized sequences — mostly a naming and method-name difference (.append vs .push) at this level. JavaScript's array is, underneath, a specialized object — a later lab covers exactly what that means for how it stores its contents.
Dictionaries vs objects
Language design choiceperson = {"name": "Ada"}
print(person["name"])let person = { name: "Ada" };
console.log(person.name);Python's dictionary and JavaScript's object literal solve the same "named key to value" problem. JavaScript additionally lets you write person.name with a dot, and — unlike a Python dict — every JS object also participates in the prototype chain, a JavaScript-specific mechanism a later lab covers in depth.
Exceptions
General programming concepttry:
risky()
except ValueError as e:
print(e)try {
risky();
} catch (e) {
console.log(e.message);
}Structured exception handling with try/catch is a shared, general concept — the shape is nearly identical. JavaScript doesn't have typed except ValueError-style catches; you check the error's type or message manually inside one catch block. This gets its own dedicated lab later.
Modules
Environmentfrom math_utils import addimport { add } from "./mathUtils.js";Both give each file its own scope and an explicit way to share specific things across files. JavaScript's module system arrived much later in the language's life than Python's, and is layered on top of an older, less isolated "just one shared global script" model — a later lab covers that history and why it matters.
Classes and object models
JavaScript-specific gotchaclass Dog:
def __init__(self, name):
self.name = nameclass Dog {
constructor(name) {
this.name = name;
}
}The syntax looks almost identical. Underneath, they are not the same model: Python's class system is class-based from the ground up. JavaScript's class keyword is syntax sitting on top of a fundamentally different mechanism — prototype-based inheritance, where objects link directly to other objects. Several labs later in this curriculum are dedicated entirely to that distinction.
Loose: "JavaScript has classes just like Python or C#."
More precise: modern JavaScript provides class syntax that reads similarly to Python's or C#'s, but JavaScript's underlying inheritance model is prototype-based, not class-based — a class in JS is a specific, convenient way of setting up a prototype chain, not a separate object system.
Async code (preview only — full topic much later)
Runtime / environmentasync def fetch():
data = await get_data()
return dataasync function fetch() {
let data = await getData();
return data;
}Both have async/await syntax, and both rely on an event loop underneath. Python's asyncio event loop is opt-in — most Python code is written without it. JavaScript's single-threaded, event-loop-driven execution is the default, unavoidable execution model for the entire language, in every environment. We'll come back to this in depth much later.
Loose: "JavaScript does asynchronous work."
More precise: JavaScript itself runs on a single thread with one call stack. Asynchronous work — timers, network requests, file access — is actually carried out by the host environment (the browser or Node.js), not by the JavaScript engine itself. The event loop and task/microtask queues are what decide when your JavaScript callback gets to run again, once that outside work finishes. A whole block of later labs is dedicated to this mechanism specifically.
7. Tiny Experiment: Truthiness Surprise
Primary objective: confirm the truthiness difference from the grid above, directly.
// Paste this into a JavaScript console (browser or node) — do not run it yet.
if ([]) {
console.log("truthy");
} else {
console.log("falsy");
}
If you know Python, what would if []: do there? Predict what this JavaScript version logs, then reveal.
8. Tiny Experiment: Constants Aren't Just a Convention
Primary objective: confirm that JavaScript's const is enforced by the engine, unlike Python's naming-only convention.
// Paste this into a JavaScript console (browser or node) — do not run it yet.
const MAX_SIZE = 10;
MAX_SIZE = 20;
console.log("reached the end");
If this were Python with MAX_SIZE = 10 then MAX_SIZE = 20, both lines would run fine. Predict what happens here, then reveal.
9. Class 1 Mental Model
Python and JavaScript occupy a similar part of the programming-language landscape: both are high-level, dynamically typed, garbage-collected, general-purpose languages.
That does not mean JavaScript is "Python with braces." They make different choices about scope, objects, equality, coercion, modules, execution environments, and asynchronous programming. Those differences are what the rest of this course investigates, one small experiment at a time.
Do not memorize the grids above. The point of this class was orientation — by now you should have a rough mental location for Assembly, C, C++, Rust, Go, Java, C#, Python, JavaScript, and TypeScript. Everything from here zooms in progressively deeper into JavaScript specifically.
← All labs · Class 2 — Every Language Has to Answer These Questions →