Keywords: JavaScript | prototype | inheritance | _proto__ | prototype
Abstract: This article provides an in-depth exploration of the core differences between __proto__ and prototype in JavaScript, detailing the prototype chain mechanism through constructor instantiation processes. Based on highly-rated Stack Overflow answers and ECMAScript specifications, it explains __proto__'s role as an object's internal prototype reference and prototype's function as a function object property. Multiple code examples demonstrate practical applications of prototypal inheritance, while discussing modern alternatives like Object.getPrototypeOf. Written in a rigorous technical style, it helps developers deeply understand JavaScript's prototype system.
Fundamental Concepts of the Prototype System
JavaScript employs a prototype-based object-oriented programming model where __proto__ and prototype are two crucial yet often confused concepts. Understanding their distinction is essential for mastering JavaScript's object system and inheritance mechanism.
The Nature and Role of __proto__
__proto__ is an internal property present in every JavaScript object, pointing to its prototype. During property lookup, when an object lacks a specific property, the JavaScript engine traverses up the __proto__ chain until it finds the property or reaches the end of the prototype chain.
// Example: Verifying __proto__'s role in prototype chain lookup
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return "Hello, " + this.name;
};
const person = new Person("Alice");
console.log(person.__proto__ === Person.prototype); // true
console.log(person.sayHello()); // "Hello, Alice"
From a technical implementation perspective, __proto__ directly maps to the object's internal [[Prototype]] slot. Although __proto__ enjoys broad browser support, the ECMAScript specification marks it as a legacy feature, recommending Object.getPrototypeOf() as a replacement.
The Function of the prototype Property
prototype is a property unique to function objects. When a function is called with the new operator, the newly created object's __proto__ is set to the function's prototype property.
// Example: Relationship between constructor functions and prototype
function Animal(type) {
this.type = type;
}
Animal.prototype.getType = function() {
return this.type;
};
const dog = new Animal("mammal");
const cat = new Animal("mammal");
console.log(dog.__proto__ === Animal.prototype); // true
console.log(cat.__proto__ === Animal.prototype); // true
console.log(dog.getType === cat.getType); // true, sharing prototype methods
This mechanism enables prototype-based inheritance, where all objects created by the same constructor share properties and methods defined on its prototype, effectively conserving memory and supporting method reuse.
Core Difference Analysis
The fundamental distinctions between __proto__ and prototype lie in their owners and roles:
- Different Owners:
__proto__exists on all objects, whileprototypeexists only on function objects - Different Timing:
prototypeis set when the constructor is defined,__proto__is determined when the object is created - Different Lookup Directions:
__proto__is used for upward prototype chain lookup,prototypeis used for downward inheritance construction
// Example: Complete prototype chain verification
function Vehicle(wheels) {
this.wheels = wheels;
}
Vehicle.prototype.getWheels = function() {
return this.wheels;
};
function Car(brand) {
this.brand = brand;
}
// Establishing inheritance relationship
Car.prototype = Object.create(Vehicle.prototype);
Car.prototype.constructor = Car;
const myCar = new Car("Toyota");
console.log(myCar.__proto__ === Car.prototype); // true
console.log(Car.prototype.__proto__ === Vehicle.prototype); // true
console.log(Vehicle.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
Modern JavaScript Best Practices
Considering __proto__'s legacy status and potential security issues, modern JavaScript development recommends using standard APIs:
// Using standard APIs instead of __proto__
function Shape(color) {
this.color = color;
}
const circle = new Shape("red");
// Getting prototype - recommended approach
const prototype = Object.getPrototypeOf(circle);
console.log(prototype === Shape.prototype); // true
// Setting prototype - recommended approach
const newPrototype = { area: function() { return 0; } };
Object.setPrototypeOf(circle, newPrototype);
console.log(Object.getPrototypeOf(circle) === newPrototype); // true
These standard methods provide more reliable prototype manipulation, avoiding compatibility and security issues potentially caused by __proto__.
Practical Application Scenarios
Understanding the difference between __proto__ and prototype is particularly important for:
- Custom Inheritance Systems: Implementing complex object inheritance relationships
- Framework Development: Building JavaScript libraries with advanced inheritance features
- Performance Optimization: Designing prototype chains appropriately to reduce memory usage
- Code Debugging: Accurately understanding inheritance relationships between objects
// Example: Impact of dynamically modifying prototypes
function Base() {}
Base.prototype.value = 1;
function Derived() {}
Derived.prototype = Object.create(Base.prototype);
const instance1 = new Derived();
console.log(instance1.value); // 1
// Modifying base class prototype
Base.prototype.value = 2;
const instance2 = new Derived();
console.log(instance1.value); // 2, dynamic inheritance
console.log(instance2.value); // 2
This dynamic nature makes JavaScript's prototype system highly flexible but requires developers to handle prototype modifications carefully to avoid unintended side effects.
Conclusion
JavaScript's __proto__ and prototype form a powerful prototype inheritance system. prototype serves as the blueprint for function objects, defining properties and methods shared by objects created through that constructor, while __proto__ acts as the object's internal prototype reference, enabling property lookup delegation. Although __proto__ provides direct prototype access, modern development should prioritize standard APIs like Object.getPrototypeOf() and Object.setPrototypeOf(). Deeply understanding the distinctions and connections between these two concepts is key to mastering JavaScript's object-oriented programming.