✅ What is .prototype?
.prototypeis a property available only on functions (specifically constructor functions).It stores an object.
That object becomes the
[[Prototype]](a.k.a.__proto__) of all instances created from that function usingnew.
🔹 1. .prototype Exists Only on Functions
Every function in JavaScript automatically gets this property:
function Person() {}
console.log(Person.prototype); // { constructor: f Person() }Objects do NOT have
.prototypeOnly functions do
<div class="infographic-proto">
<style>
.infographic-proto {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #1a8a5f;
--bad: #c8452e;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
}
.infographic-proto[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4fbf8f;
--bad: #e0715a;
}
.infographic-proto * { box-sizing: border-box; }
.infographic-proto h1 { font-family: 'Fraunces', Georgia, serif; font-weight: 600; margin: 0; }
.infographic-proto p { margin: 0; }
.infographic-proto button { font-family: inherit; }
.pr-wrap { padding: clamp(1.25rem, 5vw, 2.5rem) clamp(1.25rem, 5vw, 3rem) 2rem; }
.pr-hero { text-align: center; margin-bottom: 1.75rem; }
.pr-hero h1 { font-size: clamp(1.4rem, 4.5vw, 1.85rem); }
.pr-hero p { color: var(--ink-soft); margin-top: 0.4rem; font-size: 0.92rem; }
.pr-lanes { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); border: 1px solid var(--line); }
@media (max-width: 560px) { .pr-lanes { grid-template-columns: 1fr; } }
.pr-lane { background: var(--paper); padding: 1.1rem 1rem 1.4rem; text-align: center; }
.pr-lane svg.pr-icon { width: 26px; height: 26px; stroke: var(--accent); }
.pr-lane .pr-code { display: block; font-family: 'IBM Plex Mono', monospace; font-size: 0.76rem; margin-top: 0.35rem; color: var(--ink); }
.pr-probe { position: relative; height: 76px; margin: 1rem 0 0.5rem; display: flex; align-items: center; justify-content: center; }
.pr-hand { font-size: 0.85rem; color: var(--ink-soft); }
.pr-result {
border: 1.5px solid var(--line);
background: var(--paper-alt);
padding: 0.4rem 0.7rem;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.72rem;
opacity: 0;
transform: translateY(6px) scale(0.9);
transition: opacity 0.3s ease, transform 0.3s ease, border-color 0.3s ease;
}
.pr-result.is-shown { opacity: 1; transform: translateY(0) scale(1); }
.pr-result.good { border-color: var(--good); color: var(--good); }
.pr-result.bad { border-color: var(--bad); color: var(--bad); }
.pr-lane.is-shaking .pr-result { animation: shakeIt 0.4s ease; }
@keyframes shakeIt { 20% { transform: translateX(-4px); } 40% { transform: translateX(4px); } 60% { transform: translateX(-3px); } 80% { transform: translateX(3px); } 100% { transform: translateX(0); } }
.pr-play { border: none; background: var(--accent); color: #fff; padding: 0.45rem 1.1rem; font-size: 0.78rem; font-weight: 600; cursor: pointer; margin-top: 0.6rem; }
.pr-play:active { transform: scale(0.96); }
.pr-caption { text-align: center; color: var(--ink-soft); font-size: 0.85rem; padding-top: 1.5rem; }
.pr-caption strong { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.infographic-proto *, .infographic-proto *::before, .infographic-proto *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="pr-wrap">
<div class="pr-hero">
<p>Try reading it off a function, then off a plain object.</p>
</div>
<div class="pr-lanes">
<div class="pr-lane" id="prFn">
<svg class="pr-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><path d="M9 17c2 0 2.8-1 2.8-2.8V10c0-2 1-3.3 3.2-3"/><path d="M9 11.2h5.7"/></svg>
<code class="pr-code">function Person() {}</code>
<div class="pr-probe">
<div class="pr-result" id="prFnResult">{ constructor: Person }</div>
</div>
<button class="pr-play" data-target="fn" type="button">Person.prototype</button>
</div>
<div class="pr-lane" id="prObj">
<svg class="pr-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>
<code class="pr-code">const p = new Person()</code>
<div class="pr-probe">
<div class="pr-result" id="prObjResult">undefined</div>
</div>
<button class="pr-play" data-target="obj" type="button">p.prototype</button>
</div>
</div>
<p class="pr-caption">Every function gets a <strong>.prototype</strong> automatically. Objects — even ones built by that function — don't.</p>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-proto')
|| document.querySelector('.infographic-proto');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
function run(kind) {
const laneId = kind === 'fn' ? 'prFn' : 'prObj';
const resultId = kind === 'fn' ? 'prFnResult' : 'prObjResult';
const lane = wrapper.querySelector('#' + laneId);
const result = wrapper.querySelector('#' + resultId);
result.classList.remove('is-shown', 'good', 'bad');
lane.classList.remove('is-shaking');
void lane.offsetWidth;
setTimeout(() => {
result.classList.add('is-shown', kind === 'fn' ? 'good' : 'bad');
if (kind === 'obj') lane.classList.add('is-shaking');
}, 60);
}
wrapper.querySelectorAll('.pr-play').forEach(btn => {
btn.addEventListener('click', () => run(btn.dataset.target));
});
})();
</script>🔹 2. Instances Get __proto__ (or [[Prototype]])
When you create an object using new, the instance's __proto__ points to the function's .prototype:
function Person() {}
const p1 = new Person();
console.log(p1.__proto__ === Person.prototype); // true.prototype belongs to the function
__proto__ belongs to the instance
These two link together to form the prototype chain.
<div class="infographic-proto2">
<style>
.infographic-proto2 {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #1a8a5f;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
}
.infographic-proto2[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4fbf8f;
}
.infographic-proto2 * { box-sizing: border-box; }
.infographic-proto2 h1 { font-family: 'Fraunces', Georgia, serif; font-weight: 600; margin: 0; }
.infographic-proto2 p { margin: 0; }
.infographic-proto2 button { font-family: inherit; }
.p2-wrap { padding: clamp(1.25rem, 5vw, 2.5rem) clamp(1.25rem, 5vw, 3rem) 2rem; }
.p2-hero { text-align: center; margin-bottom: 1.5rem; }
.p2-hero h1 { font-size: clamp(1.35rem, 4.5vw, 1.75rem); }
.p2-hero p { color: var(--ink-soft); margin-top: 0.4rem; font-size: 0.9rem; }
.p2-stage { display: flex; flex-direction: column; align-items: center; }
.p2-card { width: 200px; border: 1.5px solid var(--line); background: var(--paper-alt); padding: 0.8rem 0.9rem; text-align: center; position: relative; z-index: 2; }
.p2-card.fn { border-color: var(--accent); background: var(--accent-soft); }
.p2-card .p2-tag { font-size: 0.62rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; }
.p2-card .p2-code { display: block; font-family: 'IBM Plex Mono', monospace; font-size: 0.78rem; font-weight: 700; margin-top: 0.15rem; }
.p2-card.instance { opacity: 0; transform: translateY(-10px) scale(0.9); transition: opacity 0.4s ease, transform 0.4s ease; }
.p2-card.instance.is-shown { opacity: 1; transform: translateY(0) scale(1); }
.p2-link-row { display: flex; align-items: center; justify-content: center; gap: 0.9rem; height: 70px; }
.p2-link-col { display: flex; flex-direction: column; align-items: center; height: 70px; justify-content: center; position: relative; }
.p2-link-line { width: 2px; height: 70px; background: var(--line); position: relative; }
.p2-link-fill { position: absolute; left: 0; top: 0; width: 2px; height: 0%; background: var(--accent); transition: height 0.7s ease; }
.p2-link-icon {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.6);
width: 26px; height: 26px; border-radius: 50%; background: var(--paper);
border: 1.5px solid var(--line); display: flex; align-items: center; justify-content: center;
opacity: 0; transition: opacity 0.4s ease, transform 0.4s ease, border-color 0.4s ease;
}
.p2-link-icon svg { width: 13px; height: 13px; stroke: var(--ink-soft); transition: stroke 0.4s ease; }
.p2-link-icon.is-linked { opacity: 1; transform: translate(-50%, -50%) scale(1); border-color: var(--accent); }
.p2-link-icon.is-linked svg { stroke: var(--accent); }
.p2-link-label { font-family: 'IBM Plex Mono', monospace; font-size: 0.68rem; color: var(--ink-soft); white-space: nowrap; opacity: 0; transform: translateX(-4px); transition: opacity 0.4s ease, transform 0.4s ease; }
.p2-link-label.is-shown { opacity: 1; transform: translateX(0); }
.p2-result {
margin-top: 1rem;
border: 1.5px solid var(--line);
background: var(--paper-alt);
padding: 0.5rem 0.9rem;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.76rem;
display: flex;
align-items: center;
gap: 0.4rem;
opacity: 0;
transform: translateY(6px);
transition: opacity 0.35s ease, transform 0.35s ease, border-color 0.35s ease;
}
.p2-result.is-shown { opacity: 1; transform: translateY(0); border-color: var(--good); color: var(--good); }
.p2-result svg { width: 14px; height: 14px; flex-shrink: 0; }
.p2-play { display: block; margin: 1.25rem auto 0; border: none; background: var(--accent); color: #fff; padding: 0.5rem 1.2rem; font-size: 0.8rem; font-weight: 600; cursor: pointer; }
.p2-play:active { transform: scale(0.96); }
.p2-legend { display: flex; justify-content: center; gap: 1.6rem; margin-top: 1.4rem; font-size: 0.76rem; color: var(--ink-soft); }
.p2-legend span strong { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.infographic-proto2 *, .infographic-proto2 *::before, .infographic-proto2 *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="p2-wrap">
<div class="p2-hero">
<p>Build an instance and watch the link form.</p>
</div>
<div class="p2-stage">
<div class="p2-card fn">
<div class="p2-tag">function's own property</div>
<code class="p2-code">Person.prototype</code>
</div>
<div class="p2-link-row">
<div class="p2-link-col">
<div class="p2-link-line"><div class="p2-link-fill" id="p2Fill"></div></div>
<div class="p2-link-icon" id="p2LinkIcon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 17H7A5 5 0 0 1 7 7h2"/><path d="M15 7h2a5 5 0 1 1 0 10h-2"/><line x1="8" x2="16" y1="12" y2="12"/></svg>
</div>
</div>
<div class="p2-link-label" id="p2Label">points up<br>via __proto__</div>
</div>
<div class="p2-card instance" id="p2Instance">
<div class="p2-tag">instance's own property</div>
<code class="p2-code">p1.__proto__</code>
</div>
<div class="p2-result" id="p2Result">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
p1.__proto__ === Person.prototype → true
</div>
</div>
<button class="p2-play" id="p2Play" type="button">new Person()</button>
<div class="p2-legend">
<span><strong>.prototype</strong> — belongs to the function</span>
<span><strong>__proto__</strong> — belongs to the instance</span>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-proto2')
|| document.querySelector('.infographic-proto2');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const instance = wrapper.querySelector('#p2Instance');
const fill = wrapper.querySelector('#p2Fill');
const linkIcon = wrapper.querySelector('#p2LinkIcon');
const label = wrapper.querySelector('#p2Label');
const result = wrapper.querySelector('#p2Result');
wrapper.querySelector('#p2Play').addEventListener('click', () => {
[instance, linkIcon, label, result].forEach(el => el.classList.remove('is-shown', 'is-linked'));
fill.style.transition = 'none';
fill.style.height = '0%';
void fill.offsetWidth;
fill.style.transition = 'height 0.7s ease';
setTimeout(() => instance.classList.add('is-shown'), 50);
setTimeout(() => { fill.style.height = '100%'; }, 350);
setTimeout(() => {
linkIcon.classList.add('is-linked');
label.classList.add('is-shown');
}, 950);
setTimeout(() => result.classList.add('is-shown'), 1300);
});
})();
</script>🧩 3. Adding Methods Using .prototype
Using .prototype, you can add shared methods:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log("Hello, " + this.name);
};
const p1 = new Person("Bhaskar");
const p2 = new Person("Das");
p1.sayHello(); // works
p2.sayHello(); // works✔ Both objects share the same sayHello
✔ Memory efficient
Avoid this
function Person (name) {
this.name = name;
this.sayHello = function() {
console.log("Hello, " + this.name);
};
}We Should Avoid Defining Methods Inside the Constructor.
Because every object gets its own separate copy of the method — wasting memory.
<div class="infographic-shmeth">
<style>
.infographic-shmeth {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #1a8a5f;
--bad: #c8452e;
--bad-soft: #f7e3df;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
}
.infographic-shmeth[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4fbf8f;
--bad: #e0715a;
--bad-soft: #2e211d;
}
.infographic-shmeth * { box-sizing: border-box; }
.infographic-shmeth h1, .infographic-shmeth h2 { font-family: 'Fraunces', Georgia, serif; font-weight: 600; margin: 0; }
.infographic-shmeth p { margin: 0; }
.infographic-shmeth button { font-family: inherit; }
.sm-wrap { padding: clamp(1.25rem, 5vw, 2.5rem) clamp(1.25rem, 5vw, 3rem) 2rem; }
.sm-hero { text-align: center; margin-bottom: 1.75rem; }
.sm-hero h1 { font-size: clamp(1.5rem, 4.5vw, 2rem); }
.sm-hero p { color: var(--ink-soft); margin-top: 0.4rem; font-size: 0.92rem; }
.sm-lanes { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); border: 1px solid var(--line); }
@media (max-width: 680px) { .sm-lanes { grid-template-columns: 1fr; } }
.sm-lane { background: var(--paper); padding: 1.1rem 1rem 1.4rem; }
.sm-lane-head { text-align: center; margin-bottom: 0.9rem; }
.sm-lane-head svg { width: 20px; height: 20px; }
.sm-lane.good .sm-lane-head svg { stroke: var(--good); }
.sm-lane.bad .sm-lane-head svg { stroke: var(--bad); }
.sm-lane-head h2 { font-size: 1.02rem; margin-top: 0.3rem; }
.sm-lane-head code { display: block; font-family: 'IBM Plex Mono', monospace; font-size: 0.68rem; color: var(--ink-soft); margin-top: 0.15rem; }
.sm-stage { position: relative; min-height: 168px; }
/* method chip that sits on the prototype (shared) */
.sm-proto-method {
width: 118px; margin: 0 auto 0.7rem; text-align: center; padding: 0.35rem;
border: 1.5px solid var(--accent); background: var(--accent-soft);
font-family: 'IBM Plex Mono', monospace; font-size: 0.66rem;
opacity: 0; transform: scale(0.85); transition: opacity 0.3s ease, transform 0.3s ease;
}
.sm-proto-method.is-shown { opacity: 1; transform: scale(1); }
.sm-people { display: flex; justify-content: center; gap: 2.2rem; margin-top: 0.4rem; }
.sm-person { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; width: 96px; }
.sm-person svg.sm-avatar { width: 26px; height: 26px; stroke: var(--ink-soft); opacity: 0.3; transition: opacity 0.3s ease, stroke 0.3s ease; }
.sm-person.is-here svg.sm-avatar { opacity: 1; stroke: var(--accent); }
.sm-person .sm-pname { font-family: 'IBM Plex Mono', monospace; font-size: 0.68rem; opacity: 0.3; transition: opacity 0.3s ease; }
.sm-person.is-here .sm-pname { opacity: 1; font-weight: 700; }
/* own-copy chip for the "bad" lane */
.sm-own-method {
margin-top: 0.3rem; width: 100%; text-align: center; padding: 0.28rem 0.2rem;
border: 1.5px solid var(--bad); background: var(--bad-soft); color: var(--bad);
font-family: 'IBM Plex Mono', monospace; font-size: 0.6rem;
opacity: 0; transform: translateY(-4px); transition: opacity 0.3s ease, transform 0.3s ease;
}
.sm-own-method.is-shown { opacity: 1; transform: translateY(0); }
/* connecting lines from prototype down to each person, for shared lane */
.sm-connect { position: absolute; top: 34px; left: 50%; width: 2px; height: 0; background: var(--accent); opacity: 0; transform-origin: top; transition: opacity 0.3s ease; z-index: 0; }
.sm-counter {
display: flex; align-items: center; justify-content: center; gap: 0.4rem;
margin-top: 1rem; font-size: 0.78rem; padding: 0.4rem 0.7rem; border: 1px solid var(--line); background: var(--paper-alt);
}
.sm-lane.good .sm-counter strong { color: var(--good); }
.sm-lane.bad .sm-counter strong { color: var(--bad); }
.sm-counter svg { width: 14px; height: 14px; stroke: var(--ink-soft); }
.sm-play { display: block; margin: 0.9rem auto 0; border: none; background: var(--accent); color: #fff; padding: 0.45rem 1.1rem; font-size: 0.78rem; font-weight: 600; cursor: pointer; }
.sm-play:active { transform: scale(0.96); }
.sm-caption { text-align: center; font-size: 0.75rem; color: var(--ink-soft); padding-top: 0.7rem; min-height: 1.4em; }
@media (prefers-reduced-motion: reduce) {
.infographic-shmeth *, .infographic-shmeth *::before, .infographic-shmeth *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="sm-wrap">
<div class="sm-hero">
<p>Build two <code style="font-family:'IBM Plex Mono',monospace;">Person</code> instances each way and watch memory add up.</p>
</div>
<div class="sm-lanes">
<!-- Shared via prototype -->
<div class="sm-lane good" id="laneShared">
<div class="sm-lane-head">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
<h2>Person.prototype.sayHello</h2>
<code>defined once, outside</code>
</div>
<div class="sm-stage">
<div class="sm-proto-method" id="sharedMethod">sayHello()</div>
<div class="sm-people">
<div class="sm-person" id="sharedP1">
<svg class="sm-avatar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<div class="sm-pname">p1</div>
</div>
<div class="sm-person" id="sharedP2">
<svg class="sm-avatar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<div class="sm-pname">p2</div>
</div>
</div>
</div>
<div class="sm-counter">copies of sayHello() in memory: <strong id="sharedCount">0</strong></div>
<button class="sm-play" data-lane="shared" type="button">new Person() ×2</button>
<p class="sm-caption">Both instances point to the same function.</p>
</div>
<!-- Duplicated inside constructor -->
<div class="sm-lane bad" id="laneDup">
<div class="sm-lane-head">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
<h2>this.sayHello = function</h2>
<code>defined inside the constructor</code>
</div>
<div class="sm-stage">
<div class="sm-people" style="margin-top: 2.1rem;">
<div class="sm-person" id="dupP1">
<svg class="sm-avatar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<div class="sm-pname">p1</div>
<div class="sm-own-method" id="dupMethod1">sayHello() copy</div>
</div>
<div class="sm-person" id="dupP2">
<svg class="sm-avatar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
<div class="sm-pname">p2</div>
<div class="sm-own-method" id="dupMethod2">sayHello() copy</div>
</div>
</div>
</div>
<div class="sm-counter">copies of sayHello() in memory: <strong id="dupCount">0</strong></div>
<button class="sm-play" data-lane="dup" type="button">new Person() ×2</button>
<p class="sm-caption">Every instance gets its own separate function.</p>
</div>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-shmeth')
|| document.querySelector('.infographic-shmeth');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
function playShared() {
const method = wrapper.querySelector('#sharedMethod');
const p1 = wrapper.querySelector('#sharedP1');
const p2 = wrapper.querySelector('#sharedP2');
const count = wrapper.querySelector('#sharedCount');
[method, p1, p2].forEach(el => el.classList.remove('is-shown', 'is-here'));
count.textContent = '0';
setTimeout(() => { method.classList.add('is-shown'); count.textContent = '1'; }, 150);
setTimeout(() => p1.classList.add('is-here'), 650);
setTimeout(() => p2.classList.add('is-here'), 1050);
}
function playDup() {
const p1 = wrapper.querySelector('#dupP1');
const p2 = wrapper.querySelector('#dupP2');
const m1 = wrapper.querySelector('#dupMethod1');
const m2 = wrapper.querySelector('#dupMethod2');
const count = wrapper.querySelector('#dupCount');
[p1, p2, m1, m2].forEach(el => el.classList.remove('is-shown', 'is-here'));
count.textContent = '0';
setTimeout(() => { p1.classList.add('is-here'); }, 150);
setTimeout(() => { m1.classList.add('is-shown'); count.textContent = '1'; }, 550);
setTimeout(() => { p2.classList.add('is-here'); }, 1050);
setTimeout(() => { m2.classList.add('is-shown'); count.textContent = '2'; }, 1450);
}
wrapper.querySelectorAll('.sm-play').forEach(btn => {
btn.addEventListener('click', () => {
if (btn.dataset.lane === 'shared') playShared();
else playDup();
});
});
})();
</script>🏗 4. Constructor Property
Every .prototype object has a constructor property pointing back to the function:
Person.prototype.constructor === Person // true
console.log(Person.prototype); // { constructor: f Person() }Useful for identifying which constructor created an object.
<div class="infographic-ctorprop">
<style>
.infographic-ctorprop {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #1a8a5f;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
}
.infographic-ctorprop[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4fbf8f;
}
.infographic-ctorprop * { box-sizing: border-box; }
.infographic-ctorprop h1 { font-family: 'Fraunces', Georgia, serif; font-weight: 600; margin: 0; }
.infographic-ctorprop p { margin: 0; }
.infographic-ctorprop button { font-family: inherit; }
.cp-wrap { padding: clamp(1.25rem, 5vw, 2.5rem) clamp(1.25rem, 5vw, 3rem) 2rem; }
.cp-hero { text-align: center; margin-bottom: 1.6rem; }
.cp-hero h1 { font-size: clamp(1.35rem, 4.5vw, 1.8rem); }
.cp-hero p { color: var(--ink-soft); margin-top: 0.4rem; font-size: 0.9rem; }
.cp-loop { display: flex; flex-direction: column; align-items: center; }
.cp-box { width: 190px; border: 1.5px solid var(--line); background: var(--paper-alt); padding: 0.7rem 0.9rem; text-align: center; position: relative; z-index: 2; }
.cp-box.top { border-color: var(--accent); background: var(--accent-soft); }
.cp-box .cp-tag { font-size: 0.6rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; }
.cp-box .cp-code { display: block; font-family: 'IBM Plex Mono', monospace; font-size: 0.78rem; font-weight: 700; margin-top: 0.15rem; }
.cp-rails { display: flex; justify-content: center; gap: 2.6rem; height: 84px; position: relative; }
.cp-rail { display: flex; flex-direction: column; align-items: center; width: 100px; position: relative; }
.cp-rail-line { width: 2px; height: 84px; background: var(--line); position: relative; }
.cp-rail-fill { position: absolute; left: 0; width: 2px; background: var(--accent); transition: height 0.7s ease; }
.cp-rail.down .cp-rail-fill { top: 0; height: 0%; }
.cp-rail.up .cp-rail-fill { bottom: 0; height: 0%; }
.cp-rail-arrow { position: absolute; font-size: 0.85rem; color: var(--line); transition: color 0.4s ease; }
.cp-rail.down .cp-rail-arrow { bottom: -2px; }
.cp-rail.up .cp-rail-arrow { top: -2px; transform: rotate(180deg); }
.cp-rail.is-lit .cp-rail-arrow { color: var(--accent); }
.cp-rail-label { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font-family: 'IBM Plex Mono', monospace; font-size: 0.64rem; color: var(--ink-soft); background: var(--paper); padding: 0.1rem 0.3rem; white-space: nowrap; opacity: 0.5; transition: opacity 0.4s ease, color 0.4s ease; }
.cp-rail.is-lit .cp-rail-label { opacity: 1; color: var(--accent); font-weight: 600; }
.cp-result {
margin-top: 1rem;
border: 1.5px solid var(--line);
background: var(--paper-alt);
padding: 0.5rem 0.9rem;
font-family: 'IBM Plex Mono', monospace;
font-size: 0.76rem;
display: flex;
align-items: center;
gap: 0.4rem;
opacity: 0;
transform: translateY(6px);
transition: opacity 0.35s ease, transform 0.35s ease, border-color 0.35s ease;
}
.cp-result.is-shown { opacity: 1; transform: translateY(0); border-color: var(--good); color: var(--good); }
.cp-result svg { width: 14px; height: 14px; flex-shrink: 0; }
.cp-play { display: block; margin: 1.25rem auto 0; border: none; background: var(--accent); color: #fff; padding: 0.5rem 1.2rem; font-size: 0.8rem; font-weight: 600; cursor: pointer; }
.cp-play:active { transform: scale(0.96); }
.cp-caption { text-align: center; font-size: 0.8rem; color: var(--ink-soft); margin-top: 1.1rem; }
.cp-caption strong { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.infographic-ctorprop *, .infographic-ctorprop *::before, .infographic-ctorprop *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="cp-wrap">
<div class="cp-hero">
<p>It's a loop — press play to trace it.</p>
</div>
<div class="cp-loop">
<div class="cp-box top">
<div class="cp-tag">the function</div>
<code class="cp-code">Person</code>
</div>
<div class="cp-rails">
<div class="cp-rail down" id="railDown">
<div class="cp-rail-line"><div class="cp-rail-fill" id="fillDown"></div></div>
<div class="cp-rail-label">.prototype</div>
<div class="cp-rail-arrow">▾</div>
</div>
<div class="cp-rail up" id="railUp">
<div class="cp-rail-line"><div class="cp-rail-fill" id="fillUp"></div></div>
<div class="cp-rail-label">.constructor</div>
<div class="cp-rail-arrow">▾</div>
</div>
</div>
<div class="cp-box">
<div class="cp-tag">its prototype object</div>
<code class="cp-code">Person.prototype</code>
</div>
<div class="cp-result" id="cpResult">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
Person.prototype.constructor === Person → true
</div>
</div>
<button class="cp-play" id="cpPlay" type="button">Trace it</button>
<p class="cp-caption">Handy for asking an object <strong>"which function built you?"</strong></p>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-ctorprop')
|| document.querySelector('.infographic-ctorprop');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const railDown = wrapper.querySelector('#railDown');
const railUp = wrapper.querySelector('#railUp');
const fillDown = wrapper.querySelector('#fillDown');
const fillUp = wrapper.querySelector('#fillUp');
const result = wrapper.querySelector('#cpResult');
wrapper.querySelector('#cpPlay').addEventListener('click', () => {
[railDown, railUp].forEach(r => r.classList.remove('is-lit'));
result.classList.remove('is-shown');
[fillDown, fillUp].forEach(f => {
f.style.transition = 'none';
f.style.height = '0%';
void f.offsetWidth;
f.style.transition = 'height 0.7s ease';
});
setTimeout(() => {
railDown.classList.add('is-lit');
fillDown.style.height = '100%';
}, 150);
setTimeout(() => {
railUp.classList.add('is-lit');
fillUp.style.height = '100%';
}, 950);
setTimeout(() => result.classList.add('is-shown'), 1650);
});
})();
</script>❓Why Prototypes Exist
1. To Enable Inheritance in JavaScript
Before class syntax existed, prototypes allowed:
shared behavior
method reuse
Without prototypes:
❌ duplicated code
❌ wasted memory
With prototypes:
✅ one shared method
✅ clean memory usage
2. To Avoid Copying Common Methods
Methods like:
toString()hasOwnProperty()isPrototypeOf()
are not copied to every object.
They live inside:
Object.prototypeSo all objects can access them through inheritance instead of duplication.
Object.prototype is the root prototype of almost everything in JavaScript.