🔰 Objects in JavaScript
In real life, an object is anything that has properties and characteristics, such as a car, a house, a person, or an animal. For example, a car has properties like color, brand, and speed.
Similarly, in JavaScript, an object is a data structure used to store multiple related values in a single place as key-value pairs. This makes it easy to organize and manage related information together, such as storing a person's name, age, and city inside one object.
<div class="infographic-jsobjcar">
<style>
.infographic-jsobjcar {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--line: #ddd6c9;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--ok: #1a7f4e;
--ok-soft: #e3f5ec;
--display-font: 'Fraunces', Georgia, serif;
--body-font: 'Inter', -apple-system, sans-serif;
--mono-font: 'IBM Plex Mono', 'Courier New', monospace;
margin: 0 auto;
box-sizing: border-box;
font-family: var(--body-font);
color: var(--ink);
background: var(--paper);
}
.infographic-jsobjcar[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--line: #2c313d;
--accent: #5b8def;
--accent-soft:#202942;
--ok: #5cd6a0;
--ok-soft: #16342a;
}
.infographic-jsobjcar * { box-sizing: border-box; }
.infographic-jsobjcar .ig-inner { padding: 1.75rem clamp(1.25rem, 5vw, 3rem) 2rem; }
.infographic-jsobjcar .ig-title {
font-family: var(--display-font); font-size: clamp(1.4rem, 4.5vw, 1.9rem);
font-weight: 600; text-align: center; margin: 0 0 0.4rem;
}
.infographic-jsobjcar .ig-sub {
text-align: center; font-size: 0.85rem; color: var(--ink-soft); margin: 0 0 1.5rem;
}
.infographic-jsobjcar .controls { display: flex; justify-content: center; gap: 0.6rem; margin-bottom: 1.5rem; }
.infographic-jsobjcar .ctrl-btn {
font: inherit; font-size: 0.82rem; font-weight: 600; border: 1px solid var(--line);
background: var(--paper-alt); color: var(--ink); padding: 0.5rem 1.1rem;
border-radius: 999px; cursor: pointer;
}
.infographic-jsobjcar .ctrl-btn:hover { border-color: var(--accent); color: var(--accent); }
.infographic-jsobjcar .ctrl-btn.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
/* Stage */
.infographic-jsobjcar .stage { perspective: 900px; display: flex; flex-direction: column; align-items: center; }
.infographic-jsobjcar .tag-row { display: flex; gap: 0.5rem; justify-content: center; min-height: 2.4rem; flex-wrap: wrap; }
.infographic-jsobjcar .prop-tag, .infographic-jsobjcar .method-tag {
font-family: var(--mono-font); font-size: 0.72rem; font-weight: 700; padding: 0.3rem 0.6rem;
border-radius: 999px; opacity: 0; transform: translateY(-8px) scale(0.7);
transition: opacity 0.35s ease, transform 0.35s ease;
}
.infographic-jsobjcar .prop-tag { border: 1px solid var(--accent); color: var(--accent); background: var(--accent-soft); }
.infographic-jsobjcar .method-tag { border: 1px solid var(--ok); color: var(--ok); background: var(--ok-soft); }
.infographic-jsobjcar .prop-tag.is-in, .infographic-jsobjcar .method-tag.is-in { opacity: 1; transform: translateY(0) scale(1); }
.infographic-jsobjcar .car-wrap { margin: 0.6rem 0; transform-style: preserve-3d; }
.infographic-jsobjcar .car-svg {
width: 11rem; height: auto; display: block;
animation: car-spin 3.4s linear infinite; animation-play-state: paused;
filter: drop-shadow(0 6px 10px rgba(0,0,0,0.18));
}
.infographic-jsobjcar .car-wrap.is-spinning .car-svg { animation-play-state: running; }
@keyframes car-spin {
0% { transform: rotateY(0deg) scaleX(1); }
25% { transform: rotateY(90deg) scaleX(0.25); }
50% { transform: rotateY(180deg) scaleX(1); }
75% { transform: rotateY(270deg) scaleX(0.25); }
100% { transform: rotateY(360deg) scaleX(1); }
}
/* Code block */
.infographic-jsobjcar .code-block {
font-family: var(--mono-font); font-size: 0.82rem; line-height: 1.65;
background: var(--paper-alt); border: 1px solid var(--line); border-radius: 6px;
padding: 0.9rem 1rem; margin-top: 1.25rem; min-height: 3.5rem;
}
.infographic-jsobjcar .code-block .kw { color: var(--accent); }
.infographic-jsobjcar .code-line { opacity: 0; transform: translateX(-6px); transition: opacity 0.3s ease, transform 0.3s ease; }
.infographic-jsobjcar .code-line.is-in { opacity: 1; transform: translateX(0); }
.infographic-jsobjcar .code-line.method-line { color: var(--ok); }
.infographic-jsobjcar .code-line.prop-line { color: var(--accent); }
.infographic-jsobjcar .caption {
text-align: center; font-size: 0.85rem; color: var(--ink-soft); margin-top: 1.1rem; min-height: 1.2em;
}
.infographic-jsobjcar .caption strong { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.infographic-jsobjcar *, .infographic-jsobjcar *::before, .infographic-jsobjcar *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="ig-inner">
<h2 class="ig-title">Objects in JavaScript</h2>
<p class="ig-sub">a car has properties (what it is) and methods (what it does)</p>
<div class="controls">
<button class="ctrl-btn primary" id="playBtn">▶ Play</button>
<button class="ctrl-btn" id="restartBtn">⟲ Restart</button>
</div>
<div class="stage">
<div class="tag-row" id="propRow"></div>
<div class="car-wrap" id="carWrap">
<svg class="car-svg" viewBox="0 0 240 110" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="120" cy="95" rx="100" ry="7" fill="#000" opacity="0.12"></ellipse>
<path d="M18,80 Q8,80 8,68 L8,58 Q8,47 24,44 L58,42 Q76,18 112,16 L148,16 Q178,17 190,42 L214,44 Q232,47 232,62 L232,70 Q232,80 222,80 Z"
fill="#dc2626" stroke="#7f1d1d" stroke-width="2.5"></path>
<path d="M120,80 L118,44 L58,42 Q76,18 112,16 L120,16 Z" fill="#f04444" opacity="0.55"></path>
<path d="M68,40 Q84,22 111,20 L112,40 Z" fill="#bfe3ff" stroke="#7f1d1d" stroke-width="1.5"></path>
<path d="M116,20 L148,20 Q172,21 183,40 L116,40 Z" fill="#bfe3ff" stroke="#7f1d1d" stroke-width="1.5"></path>
<rect x="222" y="52" width="10" height="9" rx="2.5" fill="#fff3b0"></rect>
<rect x="8" y="52" width="10" height="9" rx="2.5" fill="#ffb3b3"></rect>
<rect x="30" y="66" width="170" height="4" rx="2" fill="#7f1d1d" opacity="0.5"></rect>
<circle cx="62" cy="82" r="19" fill="#1a1a1a"></circle>
<circle cx="62" cy="82" r="10" fill="#d9d9d9"></circle>
<circle cx="62" cy="82" r="3.5" fill="#1a1a1a"></circle>
<circle cx="182" cy="82" r="19" fill="#1a1a1a"></circle>
<circle cx="182" cy="82" r="10" fill="#d9d9d9"></circle>
<circle cx="182" cy="82" r="3.5" fill="#1a1a1a"></circle>
</svg>
</div>
<div class="tag-row" id="methodRow"></div>
</div>
<div class="code-block" id="codeBlock">
<div class="code-line" id="lineOpen"><span class="kw">const</span> car = {</div>
<div id="propLines"></div>
<div id="methodLines"></div>
<div class="code-line" id="lineClose">};</div>
</div>
<p class="caption" id="caption">Press Play to build the car object, one piece at a time.</p>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-jsobjcar')
|| document.querySelector('.infographic-jsobjcar');
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 PROPS = [
{ key: 'name', val: '"Fiat"', tag: 'name: Fiat' },
{ key: 'model', val: '"500"', tag: 'model: 500' },
{ key: 'weight', val: '"850kg"', tag: 'weight: 850kg' },
{ key: 'color', val: '"red"', tag: 'color: red' }
];
const METHODS = [
{ key: 'start', tag: 'start()' },
{ key: 'drive', tag: 'drive()' },
{ key: 'brake', tag: 'brake()' },
{ key: 'stop', tag: 'stop()' }
];
const playBtn = wrapper.querySelector('#playBtn');
const restartBtn = wrapper.querySelector('#restartBtn');
const carWrap = wrapper.querySelector('#carWrap');
const propRow = wrapper.querySelector('#propRow');
const methodRow = wrapper.querySelector('#methodRow');
const propLines = wrapper.querySelector('#propLines');
const methodLines = wrapper.querySelector('#methodLines');
const lineOpen = wrapper.querySelector('#lineOpen');
const lineClose = wrapper.querySelector('#lineClose');
const caption = wrapper.querySelector('#caption');
let timer = null;
let idx = -1;
let steps = [];
function buildDom() {
propRow.innerHTML = '';
methodRow.innerHTML = '';
propLines.innerHTML = '';
methodLines.innerHTML = '';
lineOpen.classList.remove('is-in');
lineClose.classList.remove('is-in');
carWrap.classList.remove('is-spinning');
PROPS.forEach(p => {
const tag = document.createElement('span');
tag.className = 'prop-tag';
tag.textContent = p.tag;
tag.id = 'ptag-' + p.key;
propRow.appendChild(tag);
});
METHODS.forEach(m => {
const tag = document.createElement('span');
tag.className = 'method-tag';
tag.textContent = m.tag;
tag.id = 'mtag-' + m.key;
methodRow.appendChild(tag);
});
}
function buildSteps() {
steps = [];
steps.push({ type: 'open' });
PROPS.forEach(p => steps.push({ type: 'prop', p }));
METHODS.forEach(m => steps.push({ type: 'method', m }));
steps.push({ type: 'close' });
}
function applyStep(step) {
if (step.type === 'open') {
carWrap.classList.add('is-spinning');
lineOpen.classList.add('is-in');
caption.innerHTML = `<strong>car</strong> starts as an empty object`;
} else if (step.type === 'prop') {
const tag = wrapper.querySelector('#ptag-' + step.p.key);
tag.classList.add('is-in');
const line = document.createElement('div');
line.className = 'code-line prop-line';
line.textContent = ` ${step.p.key}: ${step.p.val},`;
propLines.appendChild(line);
requestAnimationFrame(() => line.classList.add('is-in'));
caption.innerHTML = `<strong>${step.p.key}</strong> is a property — it describes the car`;
} else if (step.type === 'method') {
const tag = wrapper.querySelector('#mtag-' + step.m.key);
tag.classList.add('is-in');
const line = document.createElement('div');
line.className = 'code-line method-line';
line.textContent = ` ${step.m.key}() { /* ... */ },`;
methodLines.appendChild(line);
requestAnimationFrame(() => line.classList.add('is-in'));
caption.innerHTML = `<strong>${step.m.key}()</strong> is a method — something the car can do`;
} else if (step.type === 'close') {
lineClose.classList.add('is-in');
caption.innerHTML = `<strong>That's an object</strong> — properties describe it, methods let it act`;
}
}
function stop() {
clearInterval(timer);
timer = null;
playBtn.textContent = '▶ Play';
}
function advance() {
idx++;
if (idx >= steps.length) { stop(); return; }
applyStep(steps[idx]);
if (idx >= steps.length - 1) stop();
}
function play() {
if (timer) { stop(); return; }
if (idx >= steps.length - 1) restart(false);
playBtn.textContent = '⏸ Pause';
timer = setInterval(advance, 750);
advance();
}
function restart(clearCaption = true) {
stop();
idx = -1;
buildDom();
buildSteps();
if (clearCaption) caption.textContent = 'Press Play to build the car object, one piece at a time.';
}
playBtn.addEventListener('click', play);
restartBtn.addEventListener('click', () => restart(true));
restart(true);
})();
</script>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});🔰 Object Properties
A real life car has properties like name, weight and color:
car.name = "Fiat"
car.model = "500"💠 Object Methods
A real life car has methods like start and stop
Methods are actions that can be performed on objects.
Methods are function definitions stored as property values.
car.start()
car.stop()🧱 Variables vs Objects
Objects are variables too. But objects can contain many values.
Objects store properties (values) and methods (functions).
A property is just
key: valueAlmost everything in JavaScript (except primitives) is an object:
arrays, functions, dates, math, maps, sets, etc.
✅ Variable (single value)
let car = "Fiat";✅ Object (many values)
const car = { type: "Fiat", model: "500", color: "white" };🧩 How to Create an Object
How to Define a JavaScript Object :
Using an Object Literal
Using the
new Object() ConstructorUsing an Constructor Function
Many more…
🧩 Object Literals
The object literal is one of the most popular patterns for creating objects in JavaScript because of its simplicity.
An object literal is a list of name:value pairs inside curly braces {}.
{firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"}Note:
name : value pairs are also called key : value pairs.
object literals are also called object initializers.
⭕ Creating a JavaScript Object
Spaces and line breaks don’t affect how the object is interpreted.
This is valid whether written on one line or multiple lines.
// Create an Object
const person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
console.log(person);
console.log(person.firstName);
console.log(person.lastName);
console.log(person.age);
console.log(person.eyeColor);{ firstName: 'John', lastName: 'Doe', age: 50, eyeColor: 'blue' }
John
Doe
50
blue✨Accessing Object Properties
You can access object properties in two ways:
The dot notation (
.)
objectName.propertyNameExample :
const person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
console.log(person.lastName); // Output: DoeThe array-like notation (
[]).
objectName["propertyName"]Example :
const person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
console.log(person["lastName"]); // Output: Doe🧩Adding New Properties
You can add new properties to an existing object by simply giving it a value:
Example :
person.nationality = "Indian";
console.log(person.nationality); // Output: IndianNow person becomes:
{
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue",
nationality: "Indian"
}❌ Deleting Properties
The
deletekeyword deletes a property from an object.The
deletekeyword deletes both the value of the property and the property itself.
Example :
const person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
nationality: "English"
};
delete person.age;or delete person["age"];Now person becomes:
{
firstName: "John",
lastName: "Doe",
eyeColor: "blue",
nationality: "English"
}Creating Object with new Object() constructor
You can create an empty object first, then add properties later.
const car = new Object();
car.brand = "Fiat";
car.model = "500";
car.color = "white";
console.log(car); // { brand: 'Fiat', model: '500', color: 'white' }✅ What happens here?
new Object()creates an empty objectProperties are added one by one
Not commonly used today (object literals are preferred)
You will learn about Constuctor Function method later in the OOP Section
<div class="infographic-objplay">
<style>
.infographic-objplay {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--line: #ddd6c9;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--purple: #7c3aed;
--purple-soft:#ede9fe;
--ok: #1a7f4e;
--ok-soft: #e3f5ec;
--bad: #b42318;
--bad-soft: #fbe9e7;
--display-font: 'Fraunces', Georgia, serif;
--body-font: 'Inter', -apple-system, sans-serif;
--mono-font: 'IBM Plex Mono', 'Courier New', monospace;
margin: 0 auto;
box-sizing: border-box;
font-family: var(--body-font);
color: var(--ink);
background: var(--paper);
}
.infographic-objplay[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--line: #2c313d;
--accent: #5b8def;
--accent-soft:#202942;
--purple: #a78bfa;
--purple-soft:#2c2140;
--ok: #5cd6a0;
--ok-soft: #16342a;
--bad: #e57373;
--bad-soft: #3a2222;
}
.infographic-objplay * { box-sizing: border-box; }
.infographic-objplay .ig-inner { padding: 1.75rem clamp(1.25rem, 5vw, 3rem) 2rem; }
.infographic-objplay .ig-title {
font-family: var(--display-font); font-size: clamp(1.4rem, 4.5vw, 1.9rem);
font-weight: 600; text-align: center; margin: 0 0 1.5rem;
}
/* Object visual */
.infographic-objplay .obj-tag {
text-align: center; font-family: var(--mono-font); font-size: 0.72rem; color: var(--purple);
margin-bottom: 0.5rem;
}
.infographic-objplay .obj-scroll { overflow-x: auto; padding-bottom: 0.3rem; }
.infographic-objplay .obj-row { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; min-width: min-content; }
.infographic-objplay .prop-chip {
font-family: var(--mono-font); font-size: 0.78rem; font-weight: 700;
padding: 0.4rem 0.7rem; border-radius: 8px; white-space: nowrap;
border: 2px solid var(--purple); background: var(--purple-soft); color: var(--purple);
transition: transform 0.25s ease, opacity 0.25s ease;
}
.infographic-objplay .prop-chip .k { opacity: 0.75; }
.infographic-objplay .prop-chip.pop-in { animation: op-pop 0.35s ease; }
.infographic-objplay .prop-chip.pop-out { animation: op-out 0.3s ease forwards; }
@keyframes op-pop { 0% { transform: scale(0.4); opacity: 0; } 60% { transform: scale(1.1); } 100% { transform: scale(1); opacity: 1; } }
@keyframes op-out { 0% { transform: scale(1); opacity: 1; } 100% { transform: scale(0.4); opacity: 0; } }
.infographic-objplay .obj-empty-msg { text-align: center; color: var(--ink-soft); font-family: var(--mono-font); font-size: 0.85rem; padding: 0.5rem; }
.infographic-objplay .reset-row { display: flex; justify-content: center; margin: 0.85rem 0 1.5rem; }
.infographic-objplay .reset-btn {
font: inherit; font-size: 0.78rem; font-weight: 700; font-family: var(--mono-font); border: 1px solid var(--line);
background: transparent; color: var(--ink-soft); padding: 0.35rem 0.85rem; border-radius: 999px; cursor: pointer;
}
.infographic-objplay .reset-btn:hover { border-color: var(--accent); color: var(--accent); }
/* Tabs + chips */
.infographic-objplay .tabs { display: flex; gap: 0.4rem; justify-content: center; flex-wrap: wrap; }
.infographic-objplay .tab {
font: inherit; font-size: 0.78rem; font-weight: 600; border: 1px solid var(--line);
background: var(--paper); color: var(--ink-soft); padding: 0.4rem 0.8rem;
border-radius: 999px; cursor: pointer;
}
.infographic-objplay .tab.is-active { background: var(--accent); color: #fff; border-color: var(--accent); }
.infographic-objplay .chips { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; margin-top: 1rem; }
.infographic-objplay .chip {
font: inherit; font-size: 0.8rem; font-weight: 700; font-family: var(--mono-font);
border: 1px solid var(--line); background: var(--paper-alt); color: var(--ink);
padding: 0.4rem 0.8rem; border-radius: 6px; cursor: pointer;
}
.infographic-objplay .chip.is-active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.infographic-objplay .playground {
margin-top: 1.5rem; background: var(--paper-alt); border: 1px solid var(--line); padding: 1.25rem 1rem;
}
.infographic-objplay .inputs-row { display: flex; flex-wrap: wrap; gap: 0.7rem; justify-content: center; }
.infographic-objplay .field { position: relative; display: flex; flex-direction: column; align-items: center; }
.infographic-objplay .field-tag { font-size: 0.62rem; font-family: var(--mono-font); color: var(--accent); margin-bottom: 0.3rem; }
.infographic-objplay .field input {
height: 2.3rem; font-family: var(--mono-font); font-size: 0.85rem; text-align: center;
border: 1px solid var(--line); background: var(--paper); color: var(--ink); border-radius: 5px; outline: none;
padding: 0 0.5rem; width: 8rem;
}
.infographic-objplay .field input:focus { border-color: var(--accent); }
.infographic-objplay .run-row { display: flex; justify-content: center; margin-top: 1rem; }
.infographic-objplay .run-btn {
font: inherit; font-size: 0.85rem; font-weight: 700; border: none; background: var(--accent);
color: #fff; padding: 0.55rem 1.3rem; border-radius: 999px; cursor: pointer;
}
.infographic-objplay .run-btn:hover:not(:disabled) { opacity: 0.9; }
.infographic-objplay .run-btn:disabled { opacity: 0.5; cursor: default; }
.infographic-objplay .call-line {
font-family: var(--mono-font); font-size: 0.85rem; text-align: center; font-weight: 700;
padding: 0.55rem 0.8rem; border-radius: 6px; margin-top: 1.1rem;
background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent);
word-break: break-word;
}
.infographic-objplay .call-line.is-delete { background: var(--bad-soft); color: var(--bad); border-color: var(--bad); }
.infographic-objplay .result-line {
text-align: center; font-family: var(--mono-font); font-size: 0.85rem; margin-top: 0.7rem;
color: var(--ink-soft); min-height: 1.3em;
}
.infographic-objplay .result-line strong { color: var(--ok); }
.infographic-objplay .caption {
text-align: center; font-size: 0.82rem; color: var(--ink-soft); margin-top: 0.75rem; min-height: 1.2em;
}
.infographic-objplay .caption strong { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.infographic-objplay *, .infographic-objplay *::before, .infographic-objplay *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="ig-inner">
<h2 class="ig-title">Object Playground</h2>
<div class="obj-tag" id="objTag">person</div>
<div class="obj-scroll"><div class="obj-row" id="objRow"></div></div>
<div class="reset-row"><button class="reset-btn" id="resetBtn">⟲ Reset</button></div>
<div class="tabs" id="tabs"></div>
<div class="chips" id="chips"></div>
<div class="playground">
<div class="inputs-row" id="inputsRow"></div>
<div class="run-row"><button class="run-btn" id="runBtn">▶ Run</button></div>
<div class="call-line" id="callLine"></div>
<div class="result-line" id="resultLine"></div>
</div>
<p class="caption" id="caption"></p>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-objplay')
|| document.querySelector('.infographic-objplay');
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 PERSON_INITIAL = { firstName: 'John', lastName: 'Doe', age: 50, eyeColor: 'blue' };
let person = Object.assign({}, PERSON_INITIAL);
let car = {};
const objTag = wrapper.querySelector('#objTag');
const objRow = wrapper.querySelector('#objRow');
const resetBtn = wrapper.querySelector('#resetBtn');
const tabsEl = wrapper.querySelector('#tabs');
const chipsEl = wrapper.querySelector('#chips');
const inputsRow = wrapper.querySelector('#inputsRow');
const runBtn = wrapper.querySelector('#runBtn');
const callLine = wrapper.querySelector('#callLine');
const resultLine = wrapper.querySelector('#resultLine');
const caption = wrapper.querySelector('#caption');
function fmtVal(v) {
if (v === undefined) return 'undefined';
if (typeof v === 'string') return `'${v}'`;
return String(v);
}
function fmtObj(obj) {
const keys = Object.keys(obj);
if (!keys.length) return '{ }';
return '{ ' + keys.map(k => `${k}: ${fmtVal(obj[k])}`).join(', ') + ' }';
}
function renderObject(obj, name, justAddedKey) {
objTag.textContent = name;
objRow.innerHTML = '';
const keys = Object.keys(obj);
if (!keys.length) {
const msg = document.createElement('div');
msg.className = 'obj-empty-msg';
msg.textContent = `${name} is empty`;
objRow.appendChild(msg);
return;
}
keys.forEach(k => {
const chip = document.createElement('span');
chip.className = 'prop-chip' + (justAddedKey === k ? ' pop-in' : '');
chip.innerHTML = `<span class="k">${k}:</span> ${obj[k]}`;
chip.id = 'chip-' + k;
objRow.appendChild(chip);
});
}
const CATEGORIES = {
'Access': {
obj: () => person, name: 'person',
methods: [
{
id: 'dot', label: 'dot notation',
inputs: [{ key: 'k', tag: 'property', default: 'lastName' }],
call: v => `person.${v.k}`,
run: v => {
const val = person[v.k];
return { msg: val === undefined ? `person.${v.k} is undefined` : `person.${v.k} is ${fmtVal(val)}` };
}
},
{
id: 'bracket', label: 'bracket notation',
inputs: [{ key: 'k', tag: 'property', default: 'lastName' }],
call: v => `person["${v.k}"]`,
run: v => {
const val = person[v.k];
return { msg: val === undefined ? `person["${v.k}"] is undefined` : `person["${v.k}"] is ${fmtVal(val)}` };
}
}
]
},
'Add': {
obj: () => person, name: 'person',
methods: [
{
id: 'add', label: 'add property',
inputs: [{ key: 'k', tag: 'property', default: 'nationality' }, { key: 'v', tag: 'value', default: 'Indian' }],
call: v => `person.${v.k} = "${v.v}"`,
run: v => { person[v.k] = v.v; return { justAdded: v.k, msg: `person now has ${Object.keys(person).length} properties` }; }
}
]
},
'Delete': {
obj: () => person, name: 'person',
methods: [
{
id: 'del', label: 'delete property',
inputs: [{ key: 'k', tag: 'property', default: 'age' }],
call: v => `delete person.${v.k}`,
isDelete: true,
run: v => {
const existed = Object.prototype.hasOwnProperty.call(person, v.k);
if (existed) {
const chip = wrapper.querySelector('#chip-' + v.k);
if (chip) chip.classList.add('pop-out');
return { deferredDelete: v.k, msg: `person.${v.k} removed` };
}
return { msg: `person has no "${v.k}" property` };
}
}
]
},
'Create': {
obj: () => car, name: 'car',
methods: [
{
id: 'newObject', label: 'new Object()',
inputs: [],
call: () => `const car = new Object();\ncar.brand = "Fiat";\ncar.model = "500";\ncar.color = "white";`,
run: () => { car = {}; return { buildCar: true, msg: `car built up one property at a time` }; }
}
]
}
};
let currentCategory = 'Access';
let currentMethod = CATEGORIES.Access.methods[0];
let values = {};
function activeObj() { return CATEGORIES[currentCategory].obj(); }
function activeName() { return CATEGORIES[currentCategory].name; }
function updatePreview() {
callLine.className = 'call-line' + (currentMethod.isDelete ? ' is-delete' : '');
callLine.textContent = currentMethod.call(values);
}
function buildInputs() {
inputsRow.innerHTML = '';
values = {};
currentMethod.inputs.forEach(spec => {
values[spec.key] = spec.default;
const field = document.createElement('div');
field.className = 'field';
const tag = document.createElement('span');
tag.className = 'field-tag';
tag.textContent = spec.tag;
const input = document.createElement('input');
input.type = 'text';
input.value = spec.default;
input.addEventListener('input', () => { values[spec.key] = input.value; updatePreview(); });
field.appendChild(tag);
field.appendChild(input);
inputsRow.appendChild(field);
});
updatePreview();
resultLine.textContent = '';
renderObject(activeObj(), activeName());
}
function selectMethod(method) {
currentMethod = method;
wrapper.querySelectorAll('.chip').forEach(c => c.classList.toggle('is-active', c.dataset.id === method.id));
buildInputs();
}
function buildChips() {
chipsEl.innerHTML = '';
CATEGORIES[currentCategory].methods.forEach((m, idx) => {
const chip = document.createElement('button');
chip.className = 'chip';
chip.textContent = m.label;
chip.dataset.id = m.id;
chip.addEventListener('click', () => selectMethod(m));
chipsEl.appendChild(chip);
if (idx === 0) selectMethod(m);
});
}
function selectCategory(name) {
currentCategory = name;
wrapper.querySelectorAll('.tab').forEach(t => t.classList.toggle('is-active', t.dataset.cat === name));
renderObject(activeObj(), activeName());
buildChips();
}
Object.keys(CATEGORIES).forEach(name => {
const tab = document.createElement('button');
tab.className = 'tab';
tab.textContent = name;
tab.dataset.cat = name;
tab.addEventListener('click', () => selectCategory(name));
tabsEl.appendChild(tab);
});
function runCarBuild() {
const props = [
{ k: 'brand', v: 'Fiat' },
{ k: 'model', v: '500' },
{ k: 'color', v: 'white' }
];
runBtn.disabled = true;
renderObject(car, 'car');
let i = 0;
const step = () => {
if (i >= props.length) { runBtn.disabled = false; return; }
car[props[i].k] = props[i].v;
renderObject(car, 'car', props[i].k);
caption.innerHTML = `<strong>car.${props[i].k}</strong> = "${props[i].v}" added`;
i++;
setTimeout(step, 500);
};
step();
}
runBtn.addEventListener('click', () => {
if (currentMethod.id === 'newObject') {
resultLine.innerHTML = `→ <strong>${currentMethod.run().msg}</strong>`;
runCarBuild();
return;
}
const outcome = currentMethod.run(values);
resultLine.innerHTML = `→ <strong>${outcome.msg}</strong>`;
if (outcome.deferredDelete) {
setTimeout(() => {
delete person[outcome.deferredDelete];
renderObject(person, 'person');
caption.innerHTML = `<strong>delete</strong> removes both the value and the property itself`;
}, 280);
} else if (outcome.justAdded) {
renderObject(person, 'person', outcome.justAdded);
caption.innerHTML = `<strong>person</strong> now has ${Object.keys(person).length} properties`;
} else {
caption.innerHTML = `${activeName()} is <strong>${fmtObj(activeObj())}</strong>`;
}
});
resetBtn.addEventListener('click', () => {
if (currentCategory === 'Create') {
car = {};
} else {
person = Object.assign({}, PERSON_INITIAL);
}
renderObject(activeObj(), activeName());
resultLine.textContent = '';
caption.textContent = `${activeName()} reset`;
});
selectCategory('Access');
})();
</script>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});