跪拜 Guibai
← All articles
Frontend · JavaScript · HTML

The Frontend Stack Nobody Teaches Together: Storage, Async Forms, and `this`

By kisshyshy ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Frontend developers regularly hit bugs where `this` is `undefined` or forms unexpectedly reload the page because the underlying binding and event-default mechanics were never laid out as a single connected system. Seeing storage, submission, and context binding together makes the patterns transferable rather than memorized trivia.

Summary

Client-side storage is a layered pyramid: HTTP cache for speed, localStorage for small persisted state, cloud object storage for shared files, Redis for microsecond KV caching, and vector databases for AI embeddings. Each tier solves a distinct latency and persistence problem. The guide maps these choices directly to real frontend architecture decisions.

Form handling has moved from full-page POST refreshes to `e.preventDefault()` plus `fetch` or AJAX, keeping UI state intact. The same event-interception pattern reappears in a complete localStorage-backed todo app that demonstrates `bind`, event delegation, and cache-busting with query-string versioning.

JavaScript's `this` is determined entirely by call site, not definition site. The six binding scenarios — bare function call, method call, reference-assignment loss, constructor invocation, event handler, and explicit `call`/`apply`/`bind` — all follow from that single rule. Arrow functions sidestep the problem by capturing the enclosing lexical scope's `this`, which is why they work predictably inside `setTimeout` and event callbacks.

Takeaways
Browser cache (strong and negotiated) sits at the fastest tier; localStorage provides synchronous 5–10 MB persistence; Redis adds microsecond KV caching in front of a database; vector databases store embeddings for semantic search.
Default HTML form submission sends a request to the `action` URL and replaces the current page, destroying client-side state.
Calling `e.preventDefault()` on the submit event and using `fetch` or `XMLHttpRequest` keeps the page alive and allows partial UI updates.
`this` is bound at call time: a bare function call gets `window` (or `undefined` in strict mode); a method call gets the owning object; a constructor call gets the new instance; an event handler gets the target element.
Assigning a method to a variable strips its context — `const fn = obj.say; fn();` loses the original `this` — and requires `.bind(obj)` to fix.
Arrow functions have no own `this`; they resolve it lexically from the enclosing scope, making them safe inside `setTimeout` and nested callbacks.
A query-string version suffix like `?v=4` on a script tag forces browsers to re-fetch the file instead of serving a stale cached copy.
Conclusions

The article treats `this` binding not as a collection of quirks but as a single rule — call site determines context — which makes the six scenarios predictable rather than arbitrary. That framing is more useful than the usual rote list of examples.

Pairing localStorage with `bind` in the todo app exposes a subtle design choice: `AddItem.bind(oForm)` lets the handler use `this` to reference the form, avoiding a hard-coded DOM query. It's a small pattern that pays off when forms are dynamically generated.

The storage pyramid from HTTP cache to vector DB is rarely presented in frontend tutorials, yet every production app sits somewhere on it. Knowing the tiers helps decide whether a feature needs a back end at all.

Concepts & terms
Strong Cache
A browser caching strategy where resources are served directly from disk or memory without any request to the server, controlled by headers like `Cache-Control: max-age` or `Expires`.
Negotiation Cache
A caching strategy where the browser sends a conditional request (e.g., `If-None-Match` or `If-Modified-Since`) and the server responds with a 304 Not Modified if the resource hasn't changed, saving bandwidth.
Lexical Scoping (for `this`)
Arrow functions do not get their own `this` binding; instead they look up `this` in the enclosing function's scope at the time they are defined, which is why they reliably preserve the outer context inside callbacks.
Event Delegation
A pattern where a single event listener is attached to a parent element and uses `event.target` to determine which child triggered the event, avoiding the need to attach listeners to each child individually.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗