Just a moment — gathering the notes
A personal collection of thoughts about software engineering, psychology, and philosophy.
Deep copy creates a fully independent duplicate of an object including all nested data, while shallow copy only duplicates the top-level structure and keeps nested references shared, making the choice between them a matter of intentional data design rather than safety alone.
Object.seal and Object.freeze restrict how objects can be modified, with sealing locking the structure while allowing value changes, and freezing making both structure and values immutable, though only at the top level.
Property attributes in JavaScript define how an object’s properties behave—whether they can be modified (writable), listed (enumerable), or reconfigured (configurable)—turning each property into a value governed by rules rather than just data.
MVVM separates data, UI, and a reactive ViewModel layer that automatically synchronizes state and interface, removing the need for manual DOM updates and shifting focus to state-driven design.
MVC separates an application into Model (data), View (UI), and Controller (logic), creating clear boundaries that improve maintainability and make complex systems easier to reason about.
The singleton pattern ensures that only one instance of an object exists and is shared across an application, providing a single source of truth while introducing trade-offs around global state and tight coupling.
The observer pattern allows a single source of change to notify multiple subscribers automatically, decoupling the producer from its consumers and enabling flexible, reactive systems.
The factory pattern centralizes object creation into a single function, allowing complex or varying object structures to be managed in one place while keeping the rest of the code decoupled from how objects are constructed.
The module pattern in JavaScript uses closures to create private state and expose a controlled public interface, helping structure code by enforcing boundaries between internal implementation and external access.
Rendering profiling analyzes how time is spent across the browser’s rendering pipeline—layout, paint, and compositing—helping identify which stage causes dropped frames and visual performance issues.
Network profiling in JavaScript analyzes the timing and sequence of network requests, helping identify performance bottlenecks by showing where time is spent during data fetching rather than in code execution.
Memory profiling in JavaScript focuses on understanding why objects remain in memory by analyzing reference lifetimes, helping identify leaks through patterns of retention rather than just memory usage size.
CPU profiling in JavaScript measures how execution time is distributed across functions, helping identify bottlenecks by showing which parts of the code consume the most time rather than relying on assumptions.
JavaScript handles concurrency not by running code in parallel but by using the event loop to schedule and interleave asynchronous tasks, allowing multiple operations to progress without blocking the single-threaded execution model.
Reflect provides a functional interface to JavaScript’s default object operations, allowing proxies to forward behavior correctly while preserving context, inheritance, and internal semantics without reimplementing them manually.
JavaScript Proxy wraps an object with a handler that intercepts operations like property access and assignment, allowing behavior to be observed or modified without changing the underlying data, effectively turning object interaction into a controllable layer.
Paint is the stage where the browser turns layout information into visual pixels by executing drawing instructions like backgrounds, borders, and text, with performance depending on how complex those visual operations are rather than just how many elements exist.
Layout (reflow) is the process where the browser calculates the size and position of elements based on DOM and CSS, resolving interdependent relationships between elements, and it becomes expensive because changes can cascade and require recalculating large portions of the page.
The browser renders CSS by parsing HTML into a DOM, parsing CSS into a CSSOM, matching styles to elements, building a render tree, calculating layout, painting pixels, and finally compositing layers, with each stage impacting performance depending on what changes.
Vue template compilation transforms template syntax into optimized render functions, allowing the framework to track reactive dependencies, distinguish static and dynamic parts, and efficiently update the DOM based on changes.
Vue diffs the virtual DOM by comparing the previous and current virtual node trees, reusing nodes with the same type and key while updating only what changed, allowing it to efficiently transform the DOM with minimal operations.
Using computed inside loops breaks its purpose as a cached, reusable derived value, since loops should only consume data while computed should prepare it once per change, not recreate it per iteration.
A computed property only tracks reactive dependencies accessed during its execution, so any non-reactive values inside it are treated as constants, meaning changes to them will not trigger recomputation or updates.
Vue watcher flush timing controls when a watcher runs relative to state changes and DOM updates—pre runs before rendering, post runs after the DOM is updated, and sync runs immediately—making timing crucial for whether your logic depends on data or the rendered UI.
Vue’s watch does not perform deep comparisons but instead compares the previous and current return values of a getter using identity, meaning it reacts to changes in references rather than inspecting internal structure unless dependency tracking is explicitly expanded with options like deep: true.
Dependency collection happens when reactive values are accessed during execution, allowing Vue to record which functions depend on them, while triggering occurs when those values change and Vue re-runs only the functions that previously accessed them.
reactive does not work with primitives because it relies on JavaScript Proxy to intercept property access, and primitives have no properties to observe, so Vue cannot track or trigger updates without wrapping them using ref.
Tree flattening in Vue is a compiler optimization where dynamic nodes are extracted from a nested template structure into a flat list, allowing updates to target only relevant parts without traversing the entire tree.
Compiler optimization in Vue is the process of analyzing templates at build time to identify static and dynamic parts, enabling Vue to generate optimized rendering code that minimizes runtime work by updating only what actually changes.
Fine-grained reactivity in Vue is a system where reactive data changes trigger updates only in the exact parts of the application that depend on that data, enabling precise and efficient UI updates.
defineExpose is a Vue <script setup> API that allows a component to explicitly expose selected internal properties or methods to its parent, creating a controlled public interface while keeping the rest encapsulated.
v-memo is a Vue directive that skips re-rendering a template subtree unless specified dependencies change, allowing developers to prevent unnecessary rendering work for performance optimization.
Vue optimizes rendering by batching updates, tracking dependencies precisely, isolating component updates, and using compiler-informed virtual DOM diffing to update only the parts of the UI that actually change.
Vue batches updates by collecting all reactive state changes within the same execution tick and applying them in a single DOM update cycle, improving performance by avoiding unnecessary repeated renders.
nextTick in Vue is a utility that waits for the framework’s asynchronous DOM update cycle to complete, ensuring that any code relying on updated DOM runs at the correct time.
watchEffect is a Vue API that automatically tracks reactive dependencies during execution and re-runs the effect when those dependencies change, trading explicit control for convenience and dynamic behavior.
readonly() in Vue creates a reactive, read-only proxy of state, allowing it to be observed but preventing direct mutation, helping enforce controlled and predictable data flow.
shallowRef and shallowReactive are Vue reactivity APIs that track only top-level changes, ignoring nested mutations, allowing more controlled and efficient state management.
Vue reactivity updates are triggered when reactive data created with ref or reactive is mutated and has been previously tracked as a dependency, allowing Vue to re-run only the affected parts of the application.
In Vue 3, Proxy is used to wrap objects and intercept property access and updates, allowing Vue to track dependencies and trigger reactive updates dynamically and efficiently.
Vue 3 differs from Vue 2 by introducing the Composition API, a Proxy-based reactivity system, improved performance, and more flexible architecture, shifting from component-based organization to composable, logic-driven structure.
A stacking context is a self-contained layering system in CSS where elements are stacked relative to each other, and the entire context is treated as a single unit in relation to other contexts.
will-change is a CSS property that hints to the browser which properties will change soon, allowing it to optimize rendering in advance for smoother performance.
On mobile devices, vh units are based on the full viewport including browser UI, which can cause layout issues since the visible viewport changes dynamically; newer units like dvh solve this by matching the actual visible height.
Relative units in CSS define sizes based on a reference such as the parent, root, or viewport, allowing layouts and typography to adapt dynamically instead of using fixed values.
box-sizing controls how an element’s width and height are calculated—either applying only to content (content-box) or including padding and border within the total size (border-box).
Quirks mode is a legacy browser rendering mode that mimics outdated, non-standard behavior to maintain compatibility with older websites, often affecting layout and CSS interpretation.
Mark-and-sweep is a garbage collection algorithm where JavaScript marks all values reachable from root references and then removes any values that are no longer reachable from the program.
JIT (Just-In-Time) compilation is a runtime optimization strategy where JavaScript engines first interpret code, then dynamically compile frequently executed parts into optimized machine code based on observed behavior.
A circular dependency occurs when modules depend on each other in a loop, which can lead to partially initialized values being accessed before they are ready, causing unexpected behavior.
Tree shaking removes unused code from a bundle by statically analyzing ES module imports, but only when it can guarantee that removing that code will not affect program behavior.
CommonJS loads modules dynamically at runtime using require, while ES Modules use static import/export syntax that is analyzed before execution, enabling better structure and optimization.
Function composition combines multiple functions into a single pipeline where each function’s output becomes the next function’s input, enabling clear and reusable data transformations.
Currying transforms a function into a sequence of functions that each take one argument, allowing context to be captured progressively and enabling more reusable, composable logic.
Debounce delays execution until activity stops, while throttle limits execution to once within a fixed time interval, allowing controlled responses to frequent events.
Object.create() creates a new object with a specified prototype, allowing it to inherit behavior by linking directly to another object rather than copying properties.
In JavaScript, prototype is a property of functions used to define shared behavior for instances, while __proto__ is a property of objects that links them to that prototype, forming the prototype chain used for property lookup.
The event loop in JavaScript is a mechanism that manages asynchronous execution by moving tasks from queues to the call stack when it becomes empty, prioritizing microtasks over macrotasks to ensure efficient and non-blocking behavior.
Execution context in JavaScript is the environment where code runs, consisting of a creation phase for setting up memory and an execution phase for running code, with each function call creating its own isolated context connected through the scope chain and managed by the call stack.
Lexical scope in JavaScript means functions access variables based on where they are defined in code, creating a predictable scope chain and enabling powerful features like closures and consistent behavior in arrow functions.
Hoisting in JavaScript is the result of the engine’s creation phase, where variables and functions are registered in memory before execution, leading to behaviors like var being initialized as undefined, let/const existing in a temporal dead zone, and function declarations being fully available before they appear in code.
VueUse is a collection of reusable Vue composables that simplify common reactive patterns, allowing developers to avoid repetitive logic and focus on building unique features.
Watchers in Vue observe reactive data and trigger side effects when changes occur, making them ideal for handling asynchronous actions, external interactions, and behavior tied to state changes.
Custom directives in Vue attach reusable, DOM-level behavior directly to elements, helping separate low-level interactions from component logic for cleaner and more focused code.
Provide and inject in Vue allow components to share context across a tree without prop drilling, enabling direct access to shared data while trading explicitness for flexibility.
Async components in Vue delay loading until needed, shifting applications from loading everything upfront to progressively loading only what matters at the right time.
Computed properties in Vue represent derived state, automatically staying in sync with their dependencies while avoiding duplication and unnecessary recalculations.
Input binding in Vue synchronizes UI and data through v-model, while modifiers refine how and when that synchronization happens—shaping both the timing and structure of user input.
Lifecycle hooks in Vue define when code should run during a component’s lifecycle, helping you align logic with creation, rendering, updates, and cleanup over time.
The Composition API shifts Vue from structured configuration to flexible logic composition, allowing developers to group related behavior together and manage complexity more explicitly as applications grow.
Old JavaScript prioritizes flexibility and quick results, while modern JavaScript emphasizes clarity, explicitness, and maintainability—shifting the focus from making code work to making it understandable over time.
Using the Options API with modern JavaScript can introduce subtle friction, as implicit this-based patterns clash with explicit, functional styles—making awareness key to avoiding hidden bugs and confusion.
Vue error handling is not just about catching failures, but about designing what users experience when things break—using error boundaries for UI recovery and global handlers for monitoring.
Vue rendering optimization is about minimizing unnecessary updates by tracking dependencies, skipping static content, and updating only what truly changes—focusing on doing less work rather than just doing things faster.
Using index as a key in Vue can cause state to stick to positions instead of actual data, because Vue uses keys to track identity over time. A proper key ensures components stay aligned with the correct data, even when the list changes.
v-cloak is a Vue directive that prevents users from seeing uncompiled template content by hiding elements until the app is fully mounted and ready. It solves a timing gap between browser rendering and Vue initialization, ensuring the UI only appears once it’s fully processed.
v-show controls visibility using CSS instead of removing elements from the DOM, making it efficient for frequently toggled UI.
v-pre tells Vue to skip compilation for a section of the template, allowing raw content to be rendered without any processing or reactivity.
v-bind connects template attributes to JavaScript expressions, while reactivity determines whether those bindings update over time.
v-text replaces an element’s entire content with a value, highlighting the difference between inserting into a template and fully overwriting it.
Directives in Vue act as structured instructions within templates, allowing dynamic behavior like conditional rendering, data binding, and event handling without sacrificing readability.
Vue templates provide a declarative way to describe UI, letting developers focus on structure and intent while the framework handles rendering and updates behind the scenes.
Attribute inheritance in Vue allows undeclared attributes to automatically pass through components to their root element, preserving flexibility while keeping components easy to use.
v-model is a shorthand for syncing state between components, wrapping the familiar pattern of props and events into a clearer, more expressive contract.
Props validation in Vue turns implicit assumptions into explicit contracts, helping components communicate what they expect without enforcing strict runtime behavior.
Global components feel effortless to use, but that convenience often shifts hidden costs into larger bundles and less control over when code is actually loaded.
NonNullable<T> removes null and undefined from a type, allowing you to express certainty—but also requiring you to take responsibility for that assumption.
Record<K, T> generates object types from a set of keys, turning repeated structures into a single, consistent pattern driven by relationships instead of manual definitions.
Omit<T, K> lets you derive a type by removing specific properties, offering a convenient but less explicit alternative to selecting fields with Pick.
Pick<T, K> allows you to derive a focused view of a type, selecting only the properties you need while keeping everything connected to the original structure.
Partial<T> reframes a strict type into a flexible version, allowing incomplete data while preserving its original structure and intent.
Function overloading allows a single function to express multiple precise input–output relationships, preserving meaning that would otherwise be lost with union types.
The satisfies keyword helps enforce type constraints without losing precise information, revealing that true strictness in TypeScript is about preserving reality, not just restricting values.
Using never correctly is less about handling errors and more about defining impossible states, allowing TypeScript to enforce that certain paths or combinations should never exist.
The difference between void and never isn’t about returning nothing, but about whether execution continues or stops entirely—shifting your thinking from values to control flow.
Tuples in TypeScript turn arrays into fixed, position-based structures, making implicit assumptions about order and meaning explicit and enforceable.
Enums in TypeScript turn raw values into named concepts, helping you move from loosely defined data to clearly expressed meaning within your system.
In JavaScript, memory doesn’t disappear when you stop using it, but when it is no longer reachable. Understanding lifecycle as a process of connection and disconnection reveals why data stays longer than expected or quietly fades away.
JavaScript doesn’t free memory based on what you no longer need, but on what is no longer reachable. Understanding memory as a network of references reveals why data stays, disappears, or unintentionally lingers.
A reflection on function borrowing in JavaScript, explaining how functions are independent from objects and how this connects behavior to data.
An exploration of closures in JavaScript, showing how functions carry their surrounding environment and why they are more about memory than just behavior.
A deeper look at JavaScript arrays, exploring how they are objects optimized for ordered data and why understanding their structure changes how you use them.
A reflection on WeakSet as a memory-aware structure, explaining how it tracks objects without owning them and avoids unintended memory retention.
A reflection on JavaScript Set as more than a duplicate remover, showing how it acts as an efficient way to track existence and enforce uniqueness by identity.
A reflection on WeakMap as a memory-aware data structure, explaining how it allows you to attach data to objects without taking ownership of their lifecycle.
A reflection on when JavaScript objects stop being the right tool, and how Map provides a more precise way to represent relationships between keys and values.
A deeper look at JSON as a cross-system data format, explaining why JavaScript intentionally removes or transforms values like functions and undefined during serialization.
A conceptual breakdown of iterables, iterators, and generators in JavaScript, showing how they work together to power loops and lazy data processing.
A deeper look at JavaScript Symbols, explaining how they prevent property collisions and act as hidden hooks that allow objects to define their own behavior within the language.
A reflection on BigInt in JavaScript, exploring why it exists, how it differs from regular numbers, and what it reveals about the constraints of evolving a language without breaking the web.
A deeper look at NaN in JavaScript, explaining why it’s still a number, how it propagates through calculations, and how to handle it safely in real applications.
An exploration of why typeof null returns "object", tracing the behavior back to JavaScript’s early implementation and the legacy decisions that still shape the language today.
An exploration of how JavaScript objects find properties through the prototype chain, and why reading, writing, and deleting properties behave differently.
A conceptual look at CSS performance optimization through the browser’s rendering pipeline, explaining why some CSS changes are expensive while others are surprisingly cheap.
One question that comes up naturally when learning JavaScript is: why does JavaScript even have two kinds of data types? Why not just treat everything the same?
When learning JavaScript, the Temporal Dead Zone (TDZ) is one of those concepts that feels confusing at first — especially if you think of it as “the time before a variable is declared.” That definition sounds logical, but it turns out to be slightly wrong.
Props in React are often described as “read-only,” but that can be misleading at first. This post breaks down what props actually are, why modifying them seems to work, and the key difference between mutation and derivation.
A common misconception in React is treating && like an if statement for conditional rendering. This post explains why that mental model breaks, how JavaScript actually evaluates &&, and why values like 0 can unexpectedly appear in your UI.
Keys in React don’t just help with lists—they define component identity. This post explains how the same component can either preserve or reset its state depending on its key, even when props change.
The cleanup function in React’s useEffect isn’t just a pattern—it’s essential for managing side effects correctly. This post explains what cleanup really means and how it prevents issues like memory leaks, duplicate intervals, and lingering event listeners in real-world scenarios.
useRef is often introduced as a way to access DOM elements, but its real purpose goes beyond that. It provides a persistent container that can store values across renders without triggering re-renders.
React keeps rendering pure, meaning components only describe UI without causing side effects. This allows React to safely re-render or discard work without bugs. Side effects are handled separately using useEffect to keep everything predictable.
useState doesn’t update values immediately. Instead, React schedules updates, batches multiple changes, and applies them in the next render. This is why repeated updates using the same state value can feel inconsistent, and why the functional update form (prev => ...) is often needed to get the correct result.
Even with well-structured global state like Zustand or Redux, not all data should live globally. useContext helps introduce boundaries by scoping state to specific parts of the component tree, making features more isolated and easier to reason about. It’s not a replacement for global state, but a way to control where state belongs.
React doesn’t update the UI immediately when state changes. It first re-runs your components to calculate what the UI should look like (render phase), and only after that applies the changes and runs effects (commit phase). This is why components must stay pure and why useEffect runs after the UI updates.
useMemo can feel unreliable at first because it’s often mistaken for a guaranteed cache. In reality, it only reuses values when the component instance stays the same and dependencies don’t change. Once you understand that it’s tied to React’s render lifecycle—not permanent storage—the behavior starts to make sense.
Using a single object with useState can organize your data, but it doesn’t organize how that data changes. useReducer goes further by centralizing all state transitions in one place, making complex logic easier to understand and maintain.
useCallback becomes useful when a function is passed to memoized child components. Without it, a new function is created on every render, causing unnecessary re-renders. By stabilizing the function reference, useCallback allows React to recognize unchanged props and skip those renders.
Hooks best practices are less about memorizing rules and more about structuring logic clearly. By keeping hooks focused, extracting reusable behavior into custom hooks, and letting components focus on UI, React code becomes easier to understand, maintain, and scale.
TanStack Router rethinks routing in React by treating routes as part of the application's architecture rather than just UI components. With strong TypeScript support, structured route trees, and built-in data loading, it offers a more predictable and scalable approach to managing navigation in modern React applications.
State management in React becomes clearer when you stop focusing on libraries and start focusing on where state lives. By distinguishing between local state, shared UI state, global client state, and server state, you can choose the right approach for each situation instead of forcing all state into a single solution.
MobX takes a reactive approach to state management in React by making state observable and letting the UI automatically update when that state changes. Instead of relying on reducers or explicit updates, components simply observe the data they use and react whenever it changes.
Zustand is a lightweight state management library for React that creates a global store outside the component tree. Components subscribe only to the parts of the state they need, allowing shared state without the boilerplate of traditional solutions like Redux.
Jotai approaches state management in React by breaking state into small independent atoms instead of a single global store. These atoms can be shared across components and composed together, allowing state to scale as a flexible dependency graph rather than a centralized structure.