Web Development
JavaScript: Language Fundamentals
1995. Netscape. Brendan Eich knocks out JavaScript in 10 days, intended as "scripting for non-programmers". Thirty years on: 98% of all websites worldwide, Node.js servicing Netflix at 70,000 requests per second. `typeof null === 'object'` - a bug that survived the browser wars. Get the "why" and the booby traps flip into a superpower.
- **Netflix** switched to Node.js and reduced application startup time by 70% - thanks to the event loop and non-blocking I/O
- **React hooks** (`useState`, `useEffect`) work on closures - each render creates a new closure with the current state
- **Cloudflare Workers** execute JavaScript on edge servers worldwide with cold start less than 5ms - faster than Lambda
Netscape, 1995: a language written in 10 days
In May 1995, Brendan Eich received a task from Netscape: create a "glue language" for HTML elements in the browser. Deadline: 10 days. He created a prototype, borrowing syntax from Java, first-class functions from Scheme, and prototypal inheritance from Self. typeof null === "object" is an artifact of that rush. The language was called Mocha, then LiveScript, then - for marketing reasons, nothing to do with Java - JavaScript. In 1997 the ECMAScript standard. In 2009 Node.js. In 2015 ES6 with classes. In 2023 - 98% of all websites.
Предварительные знания
Data Types
**JavaScript is dynamically typed.** A variable holds a number, then a string, then an object - no complaint from the runtime. Great for flexibility, brutal for subtle bugs. Understanding the type system is step zero toward predictable code.
JavaScript ships **7 primitive types** plus **1 reference type** (object). Primitives are immutable and compared by value. Objects are mutable and compared by reference.
| Type | Examples | typeof |
|---|---|---|
| string | "hello", 'world', `template` | "string" |
| number | 42, 3.14, NaN, Infinity | "number" |
| boolean | true, false | "boolean" |
| null | null | "object" (bug since 1995!) |
| undefined | undefined | "undefined" |
| symbol | Symbol('id') | "symbol" |
| bigint | 9007199254740991n | "bigint" |
| object | {}, [], function(){}, new Date() | "object" or "function" |
**`typeof null === "object"`** - not a feature, a bug from JavaScript's first release in 1995. Brendan Eich wrote the language in 10 days, and the bug got preserved for backward compatibility. To test for null, use `value === null`.
**Lifelong rule:** reach for `===` over `==` every time. `==` runs implicit type coercion under a tangle of rules that even seasoned developers cannot recite from memory. `===` compares without coercion - predictable and safe.
What will `console.log(typeof null)` output?
Closures
**Closures are the secret engine of JavaScript.** Every callback, every event handler, every module pattern leans on closures. The core idea: **a function remembers the variables from where it was born**, even when it eventually runs in a completely different context.
**Lexical Environment** - an internal object the JavaScript engine spins up on every function call. It holds local variables plus a reference to the outer environment. A closure is just a function paired with a reference to the lexical environment it was created in.
**Classic loop trap:** `for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); }` prints `3, 3, 3` - all three functions closed over the same `i`. Fix: swap `var` for `let` - `let` creates a fresh binding on every iteration.
Closures power React hooks (`useState`, `useEffect`), Express middleware, Redux, and practically every JavaScript pattern in active use. Internalize closures and the rest of the tooling stops feeling like a trick.
What will the code output: `for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); }` ?
Prototypes
**JavaScript has no classes in the classical sense.** The ES6 `class` keyword is syntactic sugar over prototypal inheritance. Every object carries a hidden `[[Prototype]]` reference to another object. Access a missing property and JavaScript walks the **prototype chain** looking for it.
**`__proto__`** - a getter/setter for the `[[Prototype]]` of an object (non-standard, universally supported). **`.prototype`** - a property on constructor functions that becomes the `[[Prototype]]` of objects built with `new`. Do not mix them: `__proto__` lives on every object; `.prototype` lives only on functions.
**Frequent interview question:** "What's the difference between `class` and a constructor function?" Answer: `class` is stricter - cannot be called without `new`, methods are non-enumerable, the body runs in strict mode. The inheritance plumbing underneath is identical: the prototype chain.
What happens when a property is accessed that does not exist on the object or anywhere in its prototype chain?
Event Loop
**JavaScript runs on a single thread.** Yet Node.js juggles thousands of parallel HTTP requests and the browser keeps the UI buttery-smooth. The trick: the **event loop** - the conductor coordinating synchronous code, callbacks, promises, and I/O. Netflix moved to Node.js and cut application startup time by 70% on the back of this exact architecture.
**Iron rule:** the microtask queue (Promise, queueMicrotask, MutationObserver) trumps the task queue (setTimeout, events). All microtasks drain before the next macrotask runs. Translation: `Promise.resolve().then(fn)` fires before `setTimeout(fn, 0)`, every time.
**`setTimeout(fn, 0)` does not mean "run in 0 ms".** It means "queue after the current stack and every pending microtask". Real-world delay clocks in at 4 ms minimum (the HTML5 cap for nested timers), plus time spent waiting in the queue.
In **Node.js** there is an extra phase: `process.nextTick()` runs even before Promises. Order of priority: Call Stack -> process.nextTick -> Microtasks (Promise) -> Macrotasks (setTimeout). Browsers have no nextTick.
JavaScript is single-threaded, so it is slow and not suitable for high-load servers
JavaScript's single-threaded nature is compensated by the event loop and non-blocking I/O. Node.js handles thousands of parallel connections in a single thread because 90% of the time a server is waiting for I/O (DB, network, files), not computing
For I/O-bound tasks (web servers, APIs, real-time apps) the event loop is more efficient than the "one thread per request" model (Java/PHP). Netflix, LinkedIn, PayPal switched to Node.js specifically for performance. For CPU-bound tasks (rendering, ML) JavaScript is indeed inferior - but that is what Worker Threads are for
In what order will these execute: `console.log('A')`, `setTimeout(() => console.log('B'), 0)`, `Promise.resolve().then(() => console.log('C'))`?
Key Ideas
- **7 primitives + object.** Primitives - by value, objects - by reference. `===` instead of `==` always. `typeof null === 'object'` - a bug since 1995
- **Closure = function + lexical environment.** Counter, module pattern, partial application. `let` instead of `var` in loops. Closures are the foundation of React hooks
- **Prototype chain - JavaScript inheritance.** `class` is sugar over prototypes. `Object.create()` for direct chain creation. A property is searched up the chain to null
- **Event loop: microtask > macrotask.** Promise.then executes before setTimeout. async/await does not block - yields control to the event loop. Single-thread + async I/O = ideal for servers
Related Topics
JavaScript is the foundation of the entire web development ecosystem:
- CSS: From Cascade to Grid — JavaScript manipulates styles via classList, style, and CSS Custom Properties
- HTML and Semantic Markup — JavaScript interacts with HTML via the DOM API (document.querySelector, createElement)
Вопросы для размышления
- Open the browser console and run: `[] == ![]`. The result is true. Can the type coercions that lead to this be explained?
- Write a function `once(fn)` that allows fn to be called only once, and returns the first result on subsequent calls. Which concept from this lesson is the key?
- A Node.js server is processing a request with heavy JSON parsing (100 MB). How will the event loop behave and what will happen to other requests?
Связанные уроки
- web-02 — JavaScript manipulates the CSS and DOM from the previous lesson
- web-04 — React, TypeScript, and modern frameworks build on top of JS fundamentals
- web-05 — Async/await and Promises extend the event loop covered here
- se-05 — The event loop is the Observer/Reactor pattern operating at the runtime level
- alg-01 — Prototype chain lookup is linear search - worth understanding its complexity
- mob-03 — SwiftUI @State and React hooks share the same declarative idea on different platforms
- comp-33-v8