% js-prototypes-objects-classes.tex — the prototype chain (drawn), lookup + shadowing,
% Object.create, `new` step by step, classes (what is not sugar), accessors, property
% descriptors, freeze/seal/preventExtensions, Proxy + Reflect (reactivity), Symbols,
% iterators + generators (coroutines), mixins.
% Source: own knowledge, aligned with ECMAScript ([[Get]]/[[Set]], OrdinaryCreateFromConstructor,
% [[HomeObject]], Proxy invariants). Senior-interview level.
% Build ONLY with: tools/print/print-sheet.py <this>.tex --dry-run
% @source: hiot monorepo, docs/school/sheets/javascript/js-prototypes-objects-classes.tex — the SOURCE OF TRUTH; a copy anywhere else (e.g. artur.gurgul.pro) is regenerated from it, never edited
% @labels: area=javascript kind=concept level=core platform=web new=no round=typescript-2026-09-24 topic=language
% @tags: prototype-chain, object-create, new-operator, classes, private-fields, property-descriptors, object-freeze, proxy, reflect, symbols, iterators, generators
\documentclass[8pt]{extarticle}
\usepackage{printup-sheet}
\usepackage{array}

\lstdefinelanguage{TSSheet}{
  morekeywords={import,from,export,default,const,let,var,type,interface,extends,function,
    return,async,await,if,else,switch,case,new,true,false,null,undefined,typeof,keyof,
    as,satisfies,never,string,number,boolean,void,declare,namespace,readonly,class,this,
    for,of,in,static,super,yield,delete,throw,try,catch,get,set},
  sensitive=true, morecomment=[l]{//}, morecomment=[s]{/*}{*/},
  morestring=[b]", morestring=[b]', morestring=[b]`}

\tikzset{
  sb/.style={box, font=\scriptsize, inner sep=1.5pt, minimum height=4.2mm},
  lbl/.style={font=\tiny, text=black!75, inner sep=1pt, align=center},
  pt/.style={font=\bfseries\small, anchor=west},
  pro/.style={->, thick, draw=sheetOrange},
  ptp/.style={->, thick, draw=sheetBlue},
}
\newcommand\fat{\hbox{=}\hbox{>}}% "=>" without the 0xProto ligature

\begin{document}

\sheettitle{Prototypes, objects and classes}{javascript · memo}

\oneliner{Every object has a hidden \texttt{[[Prototype]]} link; a read that misses \emph{own}
properties walks the chain to \texttt{null} — objects \textbf{delegate} at run time, nothing is
copied. \texttt{class} is mostly syntax over constructor functions and their \texttt{.prototype}.}

\vspace{2pt}
\noindent\begin{tikzpicture}[sheet]
  \foreach \x in {8.75,12.75} \draw[sheetGrey!40] (\x,3.1) -- (\x,-0.45);
  % ── 1 the chain ──
  \node[pt] at (0,2.95) {\textcolor{sheetBlue}{1} \texttt{class Dog extends Animal}; \texttt{d = new Dog()}};
  \node[sb, minimum width=13mm] (Dg) at (2.2,2.2) {fn \texttt{Dog}};
  \node[sb, minimum width=13mm] (An) at (4.6,2.2) {fn \texttt{Animal}};
  \node[sb, minimum width=17mm, fill=black!4, draw=sheetGrey] (FP) at (6.95,2.2) {\texttt{Function.}\\\texttt{prototype}};
  \node[sb, minimum width=11mm, draw=sheetGreen, fill=sheetGreen!10] (d) at (0.5,0.8) {\texttt{d}\\own: \texttt{name}};
  \node[sb, minimum width=17mm] (DP) at (2.2,0.8) {\texttt{Dog.prototype}\\\texttt{bark} · \texttt{constructor}};
  \node[sb, minimum width=17mm] (AP) at (4.6,0.8) {\texttt{Animal.prototype}\\\texttt{speak} · \texttt{constructor}};
  \node[sb, minimum width=17mm, fill=black!4, draw=sheetGrey] (OP) at (6.95,0.8) {\texttt{Object.prototype}\\\texttt{toString} · \texttt{hasOwn\ldots}};
  \node[lbl, font=\tiny\ttfamily] (nl) at (8.45,0.8) {null};
  \draw[pro] (d) -- (DP); \draw[pro] (DP) -- (AP); \draw[pro] (AP) -- (OP); \draw[pro] (OP) -- (nl);
  \draw[pro] (Dg) -- node[lbl, below]{statics} (An); \draw[pro] (An) -- (FP);
  \draw[ptp] ([xshift=-2mm]Dg.south) -- node[lbl, left]{\texttt{.prototype}} ([xshift=-2mm]DP.north);
  \draw[flow, dashed] ([xshift=2mm]DP.north) -- node[lbl, right]{\texttt{constructor}} ([xshift=2mm]Dg.south);
  \draw[ptp] ([xshift=-2mm]An.south) -- ([xshift=-2mm]AP.north);
  \node[lbl, anchor=west, text=sheetOrange] at (0,0.05) {orange = \texttt{[[Prototype]]}};
  \node[lbl, anchor=west, text=sheetOrange] at (0,-0.2) {(\texttt{getPrototypeOf}, \texttt{\_\_proto\_\_})};
  \node[lbl, anchor=west, text=sheetBlue] at (2.45,0.05) {blue = \texttt{.prototype}: a plain property};
  \node[lbl, anchor=west, text=sheetBlue] at (2.45,-0.2) {of constructible functions only};
  \node[lbl, anchor=west, text=sheetBrown, align=left] at (5.55,-0.1) {\texttt{d.speak()}: own? $\to$ Dog.p? $\to$\\Animal.p \checkmark{} runs with \texttt{this} = \texttt{d}};
  % ── 2 new ──
  \node[pt] at (8.85,2.95) {\textcolor{sheetBlue}{2} \texttt{new F(a)} step by step};
  \node[sb, minimum width=36mm, anchor=west] (n1) at (8.9,2.35) {\textbf{1} \texttt{o = Object.create(F.prototype)}};
  \node[sb, minimum width=36mm, anchor=west] (n2) at (8.9,1.65) {\textbf{2} run \texttt{F} with \texttt{this = o}, args \texttt{a}};
  \node[sb, minimum width=36mm, anchor=west] (n3) at (8.9,0.95) {\textbf{3} \texttt{F} returned an \emph{object}? that : \texttt{o}};
  \draw[flow] (n1) -- (n2); \draw[flow] (n2) -- (n3);
  \node[lbl, anchor=west, align=left, text=sheetBrown] at (8.85,0.25) {derived class: \texttt{this} is unbound until\\\texttt{super()} — the \emph{base} ctor allocates, using\\\texttt{new.target.prototype}};
  \node[lbl, anchor=west, text=sheetRed] at (8.85,-0.3) {class without \texttt{new} $\to$ TypeError};
  % ── 3 Proxy reactivity ──
  \node[pt] at (12.85,2.95) {\textcolor{sheetBlue}{3} Proxy reactivity (Vue 3)};
  \node[sb, minimum width=14mm, draw=sheetGreen, fill=sheetGreen!10] (ef) at (13.55,1.6) {effect /\\render};
  \node[sb, minimum width=15mm, draw=sheetOrange, fill=sheetOrange!8] (px) at (15.75,1.6) {\texttt{Proxy}\\traps};
  \node[sb, minimum width=15mm, fill=black!4, draw=sheetGrey] (tg) at (15.75,0.35) {target\\\texttt{\{count:0\}}};
  \draw[flow] ([yshift=1.2mm]ef.east) -- node[lbl, above]{read} ([yshift=1.2mm]px.west);
  \draw[hot] ([yshift=-1.2mm]px.west) -- node[lbl, below]{re-run} ([yshift=-1.2mm]ef.west-|ef.east);
  \draw[flow] (px) -- node[lbl, right, align=left]{\texttt{Reflect.}\\\texttt{get/set}} (tg);
  \node[lbl, anchor=west, align=left] at (12.85,2.45) {\texttt{get}: \texttt{track(target, key)} $\to$ dep set};
  \node[lbl, anchor=west, align=left] at (12.85,2.2) {\texttt{set}: write, then \texttt{trigger(key)}};
  \node[lbl, anchor=west, align=left, text=sheetBrown] at (12.85,0.55) {Vue 2: \texttt{defineProperty}\\getters — missed\\\emph{new} keys};
  \node[lbl, anchor=west, text=sheetBrown] at (12.85,-0.3) {MobX objects/arrays, Immer drafts: same idea};
\end{tikzpicture}

\begin{multicols}{2}

\section{How it works}
\begin{itemize}\raggedright
  \item \textbf{Read} \texttt{o.k}: own property? else \texttt{[[Prototype]]}'s, \ldots{} else
        \texttt{undefined}. A getter found up the chain runs with \texttt{this} = \texttt{o}
        (the \emph{receiver}).
  \item \textbf{Write} \texttt{o.k = v} creates/updates an \emph{own} property — \textbf{shadowing}
        the inherited one — \emph{unless} the chain has a \textbf{setter} for \texttt{k} (it
        runs) or a \textbf{non-writable} \texttt{k} (write fails; throws in strict).
  \item \texttt{Object.create(proto)} links without a constructor; \texttt{Object.create(null)}
        = a dictionary with no inherited keys. \texttt{setPrototypeOf} later deoptimises.
  \item Own: \texttt{Object.hasOwn}, \texttt{Object.keys} (own enumerable strings) · chain:
        \texttt{k in o}, \texttt{for\ldots in}. \texttt{instanceof C} = is \texttt{C.prototype}
        on the chain — fails across realms (use \texttt{Array.isArray}).
  \item \textbf{Swift:} a protocol is checked at compile time; a prototype is a live object —
        patch \texttt{Array.prototype} and every array changes now.
\end{itemize}

\section{Classes — sugar, except\ldots}
\begin{lstlisting}[language=TSSheet]
class Counter extends Base {
  #n = 0;                      // private: a brand, not a property
  static { /* static init block: runs once */ }
  inc = () => ++this.#n;       // own field, one fn per instance
  get value() { return this.#n; } // accessor on the prototype
  static is(o) { return #n in o; } // brand check
}
\end{lstlisting}
\begin{itemize}\raggedright
  \item \textbf{Not sugar}: no call without \texttt{new}; strict body; methods non-enumerable
        and not constructible; TDZ; \texttt{super()} before \texttt{this}; \texttt{extends
        Array/Error} makes real exotic instances (ES5 couldn't).
  \item \textbf{\texttt{\#private}}: invisible to reflection; \texttt{this.\#n} through a
        Proxy of the instance throws TypeError (not forwarded).
  \item \textbf{\texttt{super}} comes from the method's \texttt{[[HomeObject]]} (fixed at
        definition), not \texttt{this}: a copied method keeps it.
\end{itemize}

\section{Descriptors and locking}
\raggedright
Data \texttt{\{value, writable, enumerable, configurable\}} · accessor \texttt{\{get, set,
enumerable, configurable\}}. Literal/assignment: all \texttt{true}; \texttt{defineProperty}:
omitted = \texttt{false}. \texttt{configurable:false}: no delete, no redefine (writable may
still go true$\to$false).\\[2pt]
{\scriptsize\setlength{\tabcolsep}{3pt}
\begin{tabular}{@{}lcccl@{}}
\toprule
 & add & delete & change value & sets on every own prop \\ \midrule
\texttt{preventExtensions} & \texttimes & \checkmark & \checkmark & — \\
\texttt{seal} & \texttimes & \texttimes & \checkmark & \texttt{configurable:false} \\
\texttt{freeze} & \texttimes & \texttimes & \texttimes & + \texttt{writable:false} \\ \bottomrule
\end{tabular}}\\[1pt]
All \textbf{shallow} (nested objects stay mutable); setters still run; violations are silent
in sloppy, throw in strict.

\section{Proxy + Reflect}
\noindent\begin{minipage}{\linewidth}
\begin{lstlisting}[language=TSSheet]
const logged = t => new Proxy(t, {
  get: (t, k, r) => (log('get', k), Reflect.get(t, k, r)),
  set: (t, k, v, r) => Reflect.set(t, k, v, r) }); // false: throws
\end{lstlisting}
\end{minipage}
\texttt{r} = receiver: getters see the proxy as \texttt{this}. 13 traps (\texttt{has
deleteProperty ownKeys apply construct}\ldots); \texttt{Reflect.x} = trap \texttt{x}'s default.

\section{Symbols, iterators, generators}
\begin{itemize}\raggedright
  \item \texttt{Symbol()} = unique key, skipped by \texttt{Object.keys}/\texttt{for\ldots in}/
        \texttt{JSON}. Well-known hooks: \texttt{Symbol.iterator} (for-of, spread,
        destructuring), \texttt{asyncIterator}, \texttt{toPrimitive}.
  \item \textbf{Iterator}: \texttt{next()} $\to$ \texttt{\{value, done\}}, lazy; optional
        \texttt{return()} runs on \texttt{break} (cleanup).
  \item \texttt{function*}: calling it runs \emph{nothing}; each \texttt{next(v)} resumes to the
        next \texttt{yield}, and \texttt{v} becomes the \emph{value of the paused yield}
        — a coroutine (redux-saga; \texttt{co}, pre-async/await).
\end{itemize}
\begin{lstlisting}[language=TSSheet]
function* g() { const a = yield 1;
  const b = yield a + 1; return a + b; }
const it = g();  // nothing ran yet
it.next('x'); // {value: 1,  done: false}  first arg is ignored
it.next(10);  // a = 10 -> {value: 11, done: false}
it.next(5);   // b = 5  -> {value: 15, done: true}
it.next();    // {value: undefined, done: true}
\end{lstlisting}

\section{Mixins vs inheritance}
\raggedright One \texttt{extends}; a mixin is a class factory \texttt{B \fat{} class extends B
\{\ldots\}} — \texttt{extends Ser(Stamped(Model))} keeps \texttt{super}. Swift: protocol extensions.

\section{Interview traps}
\begin{itemize}\raggedright
  \trap{Instances link to \texttt{Dog.prototype}; \texttt{Dog} itself links to \texttt{Animal}.}
  \trap{\texttt{P.prototype.tags = []}: one array shared by every instance.}
  \trap{Spread/\texttt{assign} copy own enumerable props, run getters, drop the prototype.}
\end{itemize}

\section{Remember}
\emph{Own first, then up the chain · writes shadow · \texttt{.prototype} is for instances ·
freeze is shallow · Reflect is the default trap.}

\section{Likely questions}
\begin{enumerate}\raggedright
  \item Why pass \texttt{receiver}? — inherited getters must see the proxy as \texttt{this}.
  \item Generator vs async? — async = generator yielding promises + auto-runner.
\end{enumerate}

\end{multicols}

\noindent{\footnotesize\color{sheetGrey}\textit{Related:} js-scope-closures-this · js-async ·
js-types-coercion-modules (ToPrimitive) · Swift protocols + extensions · Obj-C \texttt{isa}}

\end{document}
