Three tools work directly with prototypes.
Object.getPrototypeOf(obj): read it
const base = { kind: "base" };
const thing = Object.create(base);
console.log(Object.getPrototypeOf(thing) === base); // → true
console.log(Object.getPrototypeOf([]) === Array.prototype); // → true
console.log(Object.getPrototypeOf("text") === String.prototype); // → true
It is the standard, reliable way to inspect a prototype.
Object.create(proto): make an object with a chosen prototype
const personMethods = {
greet() {
return `Hi, I am ${this.name}`;
}
};
const maya = Object.create(personMethods);
maya.name = "Maya";
console.log(maya.greet()); // → Hi, I am Maya
You can also pass property descriptors as a second argument, and Object.create(null) creates an object with no prototype at all.
const dictionary = Object.create(null);
dictionary.hello = "world";
console.log(dictionary.toString); // → undefined (nothing inherited)
console.log("constructor" in dictionary); // → false
A no-prototype object is a safe “plain dictionary” with no surprise keys such as constructor (see Map vs Object).
Object.setPrototypeOf(obj, proto): change it later
const a = { hello: "from a" };
const b = {};
Object.setPrototypeOf(b, a);
console.log(b.hello); // → from a
It works, but changing a prototype after creation is slow (it can undo optimisations the engine made for that object) and confusing to read. Prefer to choose the prototype when you create the object, with Object.create() or a class.
__proto__
Many older examples use obj.__proto__. It is a legacy accessor for the prototype.
const dog = { __proto__: animal }; // sets the prototype (the literal syntax is standardised)
dog.__proto__; // reads it, but avoid in new code
Use Object.getPrototypeOf() and Object.create() instead.
Checking relationships
const animal = { eats: true };
const dog = Object.create(animal);
console.log(animal.isPrototypeOf(dog)); // → true
console.log(Object.getPrototypeOf(dog) === animal); // → true
Shared methods through Object.create
const stackMethods = {
push(x) { this.items.push(x); },
pop() { return this.items.pop(); }
};
function createStack() {
const stack = Object.create(stackMethods);
stack.items = [];
return stack;
}
const s = createStack();
s.push(1);
s.push(2);
console.log(s.pop()); // → 2
All stacks share the two methods, while each has its own items. That pattern is what classes automate.