ForgeFrontend — Prepare, Practice, Crack
Secure checkout
Lifetime access
Instant PDF download
Free updates forever

Prepare · Practice · Crack

JavaScript Prototype Interview Questions

Short answer

Every JavaScript object has an internal link to another object called its prototype. When you read a property the engine walks that chain until it finds the key or reaches null. That single mechanism explains inheritance, why classes are sugar, and why methods you never defined are available on every array.

__proto__ (or getPrototypeOf)prototype
Exists onEvery objectFunctions only
What it isThe link used for lookupThe object given to instances made with new
Read it withObject.getPrototypeOf(obj)Fn.prototype
Points atThe next object in the chainThe future prototype of instances
Used at runtime forProperty lookupNothing, until you call new
The two names people confuse, which is the most-asked question here.

What is the prototype chain?

Every object carries a hidden link to another object, its prototype. When you read a property, the engine checks the object itself first; if the key is not there it follows the link and checks that object, and so on until it either finds the key or reaches `null`. That walk is the prototype chain, and it is the entirety of inheritance in JavaScript. Writing a property, by contrast, never walks the chain — it always creates or updates the key directly on the object you wrote to.

The walk, made visiblejavascript
1const arr = [1, 2, 3];
2
3console.log(arr.hasOwnProperty("map"));
4// → false        map is not on the array itself
5
6console.log(Object.getPrototypeOf(arr) === Array.prototype);
7// → true         first stop: Array.prototype, where map lives
8
9console.log(Object.getPrototypeOf(Array.prototype) === Object.prototype);
10// → true         second stop
11console.log(Object.getPrototypeOf(Object.prototype));
12// → null         end of the chain
13
14console.log(arr.toString);
15// → [Function: toString]   found two links up

That asymmetry between reading and writing is the source of a whole class of confusing behaviour. Assigning to a property that exists on the prototype does not modify the prototype — it creates a same-named property on the instance that shadows it. Every other instance still sees the original, which is why a bug like this can look like it only affects one object at random.

What is the difference between __proto__ and prototype?

They are related but different things, and mixing them up is the single most common prototype mistake. `prototype` is a property that exists only on functions, and it holds the object that will become the prototype of any instance created by calling that function with `new`. `__proto__` — properly accessed with `Object.getPrototypeOf` — exists on every object and is the actual link the engine follows during lookup.

One is a plan, the other is the linkjavascript
1function Person(name) { this.name = name; }
2Person.prototype.greet = function () { return `hi ${this.name}`; };
3
4const p = new Person("Arun");
5
6console.log(Object.getPrototypeOf(p) === Person.prototype);
7// → true          the instance's link points at the function's prototype
8
9console.log(p.prototype);
10// → undefined     instances have no `prototype` property
11console.log(typeof Person.prototype);
12// → object        functions do
13
14console.log(p.greet());
15// → hi Arun       found by walking one link up

A useful way to hold it in your head: `prototype` is a plan a function carries for objects it has not made yet, and `__proto__` is the wire an object actually uses. `__proto__` itself is legacy — it is standardised only for web compatibility, and `Object.getPrototypeOf` and `Object.setPrototypeOf` are the supported API. Mentioning that distinction is a cheap way to show you have read the modern documentation.

It is worth knowing why the chain exists at all, because the follow-up "why not just copy the methods onto every object?" does come up. Copying would mean a thousand array instances holding a thousand copies of every array method, and it would make later additions impossible — a method added after an object was created could never reach it. Linking costs one pointer per object and keeps everything live, which is the trade the language made.

What does the new keyword actually do?

This is asked constantly and has a precise four-step answer worth memorising. `new Fn(args)` creates a fresh empty object, links its prototype to `Fn.prototype`, calls `Fn` with `this` bound to that object, and returns the object — unless the constructor explicitly returns a different object, in which case that wins. Returning a primitive is ignored, which surprises people.

Implementing new by hand — a common follow-upjavascript
1function myNew(Fn, ...args) {
2  const obj = Object.create(Fn.prototype);   // steps 1 and 2
3  const result = Fn.apply(obj, args);        // step 3
4  return typeof result === "object" && result !== null ? result : obj;
5}
6
7function Person(name) { this.name = name; }
8console.log(myNew(Person, "Arun").name);
9// → Arun
10
11// The override rule, which the last line handles:
12function Weird() { this.a = 1; return { b: 2 }; }
13console.log(new Weird());
14// → { b: 2 }      the explicit object wins
15
16function Weird2() { this.a = 1; return 42; }
17console.log(new Weird2());
18// → Weird2 { a: 1 }   a returned primitive is ignored

The four steps also explain two errors people meet without understanding them. Forgetting `new` on an old-style constructor means `this` is undefined in strict mode, so the assignment throws rather than quietly writing to the global object — which is why class constructors were made to throw explicitly. And an arrow function has no `prototype` property and no own `this`, so it cannot be used with `new` at all; the engine rejects it before any of the four steps run.

Are ES6 classes just sugar over prototypes?

Underneath, yes — a class declaration produces a constructor function with its methods installed on `.prototype`, exactly as the older syntax did by hand. What classes add is a set of guardrails rather than a new object model: the body always runs in strict mode, methods are non-enumerable so they do not show up in `for…in`, calling the class without `new` throws instead of silently polluting the global object, and `extends` wires the chain for both instances and statics.

Same machinery, checked at the edgesjavascript
1class Animal {
2  constructor(name) { this.name = name; }
3  speak() { return `${this.name} makes a sound`; }
4}
5class Dog extends Animal {
6  speak() { return `${super.speak()} — a bark`; }
7}
8
9console.log(typeof Animal);
10// → function                              still a function
11console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype);
12// → true                                  the chain is the same as ever
13console.log(Object.keys(Animal.prototype));
14// → []                                    methods are non-enumerable
15
16console.log(new Dog("Rex").speak());
17// → Rex makes a sound — a bark

The one genuine addition is that `extends` also links the constructors themselves, so static methods are inherited — `Dog.someStaticFromAnimal` resolves. The old two-line pattern of `Child.prototype = Object.create(Parent.prototype)` only wired the instance side, which is why static inheritance had to be done manually. That is a good detail to have ready if someone claims classes add nothing at all.

A practical way to see all of this is to log an object in the browser console and expand the `[[Prototype]]` entry. Every method you can call but never defined is sitting one or two levels down that tree, and clicking through it once makes the chain concrete in a way that reading about it does not. It also shows you immediately whether a library has added anything to a built-in prototype.

This is 1 of 80+ questions in the JavaScript Interview Kit

Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.

⚡ Get the JavaScript Interview Kit → ₹299

How do you create an object with a specific prototype?

`Object.create(proto)` makes a new object whose prototype is exactly what you pass, with no constructor involved. Passing `null` produces an object with no prototype at all — no `toString`, no `hasOwnProperty`, nothing inherited — which is genuinely useful for dictionaries where user-controlled keys must not collide with built-in property names.

Object.create, and the null-prototype dictionaryjavascript
1const base = { greet() { return "hi"; } };
2const child = Object.create(base);
3console.log(child.greet(), Object.getPrototypeOf(child) === base);
4// → hi true
5
6const dict = Object.create(null);
7dict.constructor = "user input";
8console.log(dict.constructor);
9// → user input        no inherited property to collide with
10
11const normal = {};
12console.log(normal.constructor);
13// → [Function: Object]  inherited, and a real source of bugs
14
15console.log(Object.hasOwn(dict, "constructor"));
16// → true              hasOwn works on null-prototype objects;
17//                     dict.hasOwnProperty would throw

Null-prototype objects have become more relevant, not less, because prototype pollution is a real vulnerability class. If untrusted input is merged into an object using a naive deep merge, a key called `__proto__` can reach `Object.prototype` and change behaviour across the whole application. Using a null-prototype object for anything built from user input removes the target entirely, which is a strong thing to mention if security comes up.

Why do inherited properties break for…in and how do you avoid it?

`for…in` iterates every enumerable property in the whole chain, not just the object's own. If anything added an enumerable property to `Object.prototype` — an old polyfill, a careless library — every `for…in` loop in the application picks it up. That is why defensive `hasOwnProperty` checks used to be everywhere, and why the modern replacements exist.

The old guard and the modern alternativesjavascript
1Object.prototype.injected = "oops";     // never do this
2const o = { a: 1 };
3
4for (const k in o) console.log(k);
5// → a
6// → injected                            inherited and enumerable
7
8console.log(Object.keys(o));
9// → [ 'a' ]                             own enumerable only
10for (const k of Object.keys(o)) { /* safe */ }
11
12console.log(Object.hasOwn(o, "injected"));
13// → false                               modern, safe on null prototypes
14console.log(o.hasOwnProperty("injected"));
15// → false                               works, but breaks if shadowed

The practical rule is to reach for `Object.keys`, `Object.values` or `Object.entries` for plain objects and `for…of` for arrays, leaving `for…in` for the rare case where you genuinely want inherited keys. `Object.hasOwn` is the modern replacement for `hasOwnProperty` and is safe even when an object has a property literally named `hasOwnProperty` — a real hazard when keys come from user input.

One caveat about null-prototype objects worth stating alongside the recommendation: they lose every convenience method, so `dict.toString()` throws and logging one in some environments prints awkwardly. Use them where the keys are untrusted and the object is pure data, and use a `Map` instead when you want both safety and a real API — which is usually the better answer once you are choosing deliberately rather than defaulting to an object literal.

Why put methods on the prototype instead of in the constructor?

Memory and identity. A method defined inside the constructor is created fresh for every instance, so ten thousand objects mean ten thousand identical function objects. A method on the prototype exists once and is shared by every instance through the chain. It also means the functions compare equal across instances, which matters anywhere identity is used for change detection.

One function versus one per instancejavascript
1function A(n) {
2  this.n = n;
3  this.get = function () { return this.n; };   // new function each time
4}
5function B(n) { this.n = n; }
6B.prototype.get = function () { return this.n; };   // one, shared
7
8console.log(new A(1).get === new A(2).get);
9// → false        two separate function objects
10
11console.log(new B(1).get === new B(2).get);
12// → true         the same function, found on the prototype

What is the difference between prototypal and classical inheritance?

Classical inheritance, as in Java or C++, copies structure from a class — a blueprint that is not itself an object — into instances at creation time. Prototypal inheritance links objects to other objects, and the link is live: adding a method to a prototype makes it immediately available on every existing instance, because lookup happens at read time rather than at creation time.

The live link, which classical inheritance has no equivalent forjavascript
1function Person(name) { this.name = name; }
2const p = new Person("Arun");
3
4console.log(p.shout);
5// → undefined      does not exist yet
6
7Person.prototype.shout = function () { return this.name.toUpperCase(); };
8
9console.log(p.shout());
10// → ARUN           an object created BEFORE the method was defined

The other consequence is that there is no separate class entity to reason about: a constructor is an ordinary function and a prototype is an ordinary object, both inspectable and modifiable at runtime. That live behaviour is exactly why monkey-patching built-ins is possible and exactly why it is discouraged — adding to `Array.prototype` changes every array in the program, including ones inside libraries you did not write. Composition is generally the better answer in modern JavaScript: build objects from small functions rather than deep inheritance chains, which is the same advice that has moved React from class hierarchies to hooks.

What is the prototype of a plain object literal?

Object.prototype, which is where toString, valueOf and hasOwnProperty come from. Its own prototype is null, so a plain object's chain is two links long. Object.create(null) opts out entirely, producing an object with no inherited members at all.

Is Object.setPrototypeOf safe to use?

It works, but changing an object's prototype after creation deoptimises it badly in every major engine — property access on that object becomes much slower. Prefer Object.create to set the prototype at creation time, or a class if you want the inheritance declared up front.

What does instanceof actually check?

Whether the constructor's prototype object appears anywhere in the value's prototype chain — not what the value's type is. That is why it fails across iframes, where each window has its own Array with its own prototype, and why Array.isArray exists as a reliable alternative.

Why is modifying built-in prototypes discouraged?

Because the chain is live and global: adding to Array.prototype affects every array in the process, including ones inside dependencies. If it is enumerable it also leaks into for…in loops everywhere, and a future language version adding a method with the same name will silently conflict with yours.

How does super work under the hood?

In a derived class, super() calls the parent constructor with the same `this`, which is why `this` is unavailable until you have called it. super.method() looks the method up starting one level above the current object's prototype, so it finds the parent's version rather than recursing into itself.

Frequently asked questions

What is the prototype chain in JavaScript?
The series of objects the engine follows when looking up a property. It checks the object itself, then its prototype, then that object's prototype, until it finds the key or reaches null. That walk is how inheritance works — there is no copying, only linking.
What is the difference between __proto__ and prototype?
prototype exists only on functions and holds the object that instances created with new will link to. __proto__, properly read with Object.getPrototypeOf, exists on every object and is the actual link used during lookup. One is a plan; the other is the wire.
What does the new keyword do?
It creates an empty object, sets that object's prototype to the constructor function's prototype property, calls the constructor with this bound to the new object, and returns it. If the constructor explicitly returns an object, that object is returned instead; a returned primitive is ignored.
Are JavaScript classes real classes?
No — a class produces a constructor function with methods on its prototype, exactly like the older syntax. What it adds is enforcement: strict mode inside the body, non-enumerable methods, a throw if called without new, and inheritance of static members through extends.
What is Object.create used for?
Creating an object with a chosen prototype and no constructor call. Object.create(base) links the new object directly to base. Object.create(null) produces an object with no prototype at all, which makes it a safe dictionary for user-supplied keys.
Why should you use hasOwnProperty or Object.hasOwn?
Because in operator and for…in both see inherited properties. hasOwn checks only the object's own keys. Object.hasOwn is the modern form and is safer, since it still works when an object has no prototype or has a property literally named hasOwnProperty.
Why does for…in include unexpected keys?
It iterates every enumerable property in the whole prototype chain, so anything added to Object.prototype appears in every loop. Use Object.keys, Object.values or Object.entries for plain objects and for…of for arrays; reserve for…in for the rare case where inherited keys are wanted.
Should methods go on the prototype or in the constructor?
On the prototype, normally — one shared function instead of one per instance, which saves memory and keeps function identity stable across instances. The deliberate exception is a class field holding an arrow function, which is per-instance so that it captures this lexically.
What is the difference between prototypal and classical inheritance?
Classical inheritance copies structure from a class definition into instances at creation. Prototypal inheritance links live objects, so adding a method to a prototype makes it available on objects that already exist. Lookup happens at read time, not at construction time.
How does instanceof work?
It walks the value's prototype chain looking for the constructor's prototype object. Because it depends on identity rather than shape, it fails across realms — an array from an iframe is not instanceof the parent window's Array — which is why Array.isArray exists.
Is it bad to modify Array.prototype or Object.prototype?
Yes. The chain is global and live, so your change affects every array or object in the process, including inside libraries. An enumerable addition also leaks into every for…in loop, and a future standard method with the same name will collide with yours.
What is the prototype of a function?
Function.prototype, which is where call, apply and bind come from — and its prototype is Object.prototype. This is separate from the function's own prototype property, which is the object it hands to instances. Functions therefore participate in two different chains, which is the detail that makes this topic confusing.

This is 1 of 80+ questions in the JavaScript Interview Kit

Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.

⚡ Get the JavaScript Interview Kit → ₹299
Written by Arun Karthikeyan · Last updated

Full kit

JavaScript Interview Kit · ₹299

Get it →