What it does: Constructor functions have a prototype property that becomes the [[Prototype]] of objects created with new.
How Constructor Prototypes Work:
Basic Setup:
function Rabbit(name) {
this.name = name;
}
Rabbit.prototype = { eats: true }; // This becomes [[Prototype]] for new objects
let rabbit1 = new Rabbit("White");
let rabbit2 = new Rabbit("Black");
console.log(rabbit1.eats); // true (inherited)
console.log(rabbit2.eats); // true (inherited)The Assignment Happens at new Time:
function Dog(name) { this.name = name; }
Dog.prototype = { barks: true };
let dog1 = new Dog("Rex");
Dog.prototype = { meows: true }; // Change after creation
let dog2 = new Dog("Fluffy");
console.log(dog1.barks); // true (keeps old prototype)
console.log(dog2.barks); // undefined (has new prototype)
console.log(dog2.meows); // trueDefault F.prototype Behavior:
Every Function Gets Default Prototype:
javascript
function MyFunc() {}
// JavaScript automatically creates:
// MyFunc.prototype = { constructor: MyFunc };
console.log(MyFunc.prototype.constructor === MyFunc); // trueConstructor Property in Action:
javascript
function Car(model) { this.model = model; }
let car1 = new Car("Toyota");
let car2 = new car1.constructor("Honda"); // Same as: new Car("Honda")
console.log(car2.model); // "Honda"The Simple Rules:
F.prototype Assignment: Only matters when you call new F() Default Prototype: Always { constructor: F } Constructor Property: Points back to the original function
javascript
function Animal() {}
let animal = new Animal();
console.log(animal.constructor === Animal); // true
console.log(animal.__proto__ === Animal.prototype); // trueInterview Gotchas:
javascript
// Gotcha 1: Overwriting prototype loses constructor
function Bird() {}
Bird.prototype = { flies: true };
let bird = new Bird();
console.log(bird.constructor === Bird); // false! (lost constructor)
// Fix: Keep constructor when overwriting
Bird.prototype = {
flies: true,
constructor: Bird // Manually preserve it
};
// Gotcha 2: prototype property vs [[Prototype]]
function Fish() {}
let fish = new Fish();
Fish.prototype.swims = true; // This is F.prototype (constructor's property)
console.log(fish.__proto__.swims); // true (fish's [[Prototype]])
// Gotcha 3: Regular objects don't care about prototype property
let obj = { prototype: "whatever" };
// This does NOTHING special - just a regular propertyWhat Exists in This System:
F.prototype- constructor function’s property (not[[Prototype]])constructor- property that points back to the constructor- Default prototype -
{ constructor: F }created automatically newoperator - usesF.prototypeto set[[Prototype]]
Never Get Tricked - Follow These Rules:
- F.prototype ≠ Prototype - first is a property, second is internal link
- Assignment happens at
newtime - changing F.prototype later doesn’t affect existing objects - Constructor can be lost - if you overwrite prototype, add constructor back manually
- Only works with
new- regular function calls ignore F.prototype completely
Bottom line: Constructor functions use their prototype property as a template for what new objects should inherit from, but only when called with new.
What .prototype actually is:
function Dog(name) { this.name = name; }
// Dog.prototype is just a PROPERTY on the Dog function
// You can put anything in it: objects, functions, variables
Dog.prototype = { barks: true, tail: "wagging" };
Dog.prototype.run = function() { return "running"; };The Memory Address Connection:
function Dog(name) { this.name = name; }
Dog.prototype = { barks: true }; // This object lives at memory address X100
let dog1 = new Dog("Rex");
// dog1[[Prototype]] → points to X100 (the memory address)
// NOT to "Dog.prototype" as a concept, but to the ACTUAL OBJECT at X100
Dog.prototype = { meows: true }; // NEW object at memory address X200
// But dog1[[Prototype]] still points to X100! It's LOCKED IN.
let dog2 = new Dog("Fluffy");
// dog2[[Prototype]] → points to X200 (the new object)Visual Memory Layout:
Memory X100: { barks: true } ← dog1[[Prototype]] points here FOREVER
Memory X200: { meows: true } ← dog2[[Prototype]] points here
Dog.prototype → now points to X200 (but dog1 doesn't care!)
Why the behavior happens:
console.log(dog1.barks); // true
// dog1 looks at its [[Prototype]] → goes to X100 → finds { barks: true }
console.log(dog1.meows); // undefined
// dog1 looks at its [[Prototype]] → goes to X100 → no meows property
console.log(dog2.barks); // undefined
// dog2 looks at its [[Prototype]] → goes to X200 → no barks property
console.log(dog2.meows); // true
// dog2 looks at its [[Prototype]] → goes to X200 → finds { meows: true }The Key Rule:
- At
newtime:object[[Prototype]]gets the MEMORY ADDRESS of whateverF.prototypepoints to - After creation:
object[[Prototype]]is LOCKED to that memory address - Changing
F.prototypelater creates a NEW memory address, but existing objects don’t care
Bottom line: It’s about memory addresses, not dynamic lookups. Once created, your object’s [[Prototype]] is glued to a specific memory location forever.
