This chapter follows QuickTip: Filter object properties by key.
Every ordinary object has an internal [[Prototype]] link (exposed as Object.getPrototypeOf). When you read obj.method, the engine checks own properties first, then walks the chain until it finds a match or reaches null.
Prototype chain lookup
const animal = { speak() { return '...'; },};
const dog = Object.create(animal);dog.speak(); // '...' — found on animalObject.create(proto) builds an object whose [[Prototype]] is proto. Literal {} gets Object.prototype unless you use Object.create(null) for a null-prototype dictionary.
Constructor functions and .prototype
Before class, shared methods lived on Constructor.prototype. new creates an object whose [[Prototype]] is that prototype object.
function Person(name) { this.name = name;}Person.prototype.greet = function greet() { return `Hi, ${this.name}`;};
const ada = new Person('Ada');ada.greet(); // Hi, Adainstanceof checks whether Constructor.prototype appears anywhere on the instance’s prototype chain.
Own properties versus inherited
obj.hasOwnProperty('x') and Object.hasOwn(obj, 'x') ignore inherited keys. for...in enumerates inherited enumerable string keys unless you filter with hasOwn.
Assigning obj.method = fn creates an own property that shadows a prototype method without removing it from the prototype.
Subclassing with Object.setPrototypeOf
Prefer class extends (next chapter) for subclassing. Low-level APIs include Object.setPrototypeOf (slow path, mutates existing object) and manual prototype wiring in legacy code.
Performance note
Modern engines optimize common object shapes with hidden classes (see Hidden classes and inline caches). Stable property order and consistent initialization help; reshaping objects after creation can deoptimize hot paths.
Next: Classes in JavaScript.