Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript原型机制教程,详解prototype属性、__proto__属性、constructor属性作用。包含完整代码示例和原型链基础,适合前端开发者快速掌握JavaScript原型核心概念。
核心关键词:JavaScript原型机制2024、prototype属性、__proto__属性、constructor属性、JavaScript原型链基础
长尾关键词:JavaScript原型机制怎么理解、prototype和__proto__区别、constructor属性作用、JavaScript原型详解、原型机制工作原理
通过本节JavaScript原型机制详解,你将系统性掌握:
原型机制是JavaScript面向对象编程的基石,它实现了对象之间的继承关系和方法共享。与传统的基于类的继承不同,JavaScript采用基于原型的继承,这使得JavaScript具有了极大的灵活性和动态性。
💡 核心理解:原型机制是JavaScript"万物皆对象"理念的具体实现,掌握它就掌握了JavaScript的精髓
prototype属性是函数对象特有的属性,它指向一个对象,这个对象将成为通过该函数创建的实例的原型。
// 🎉 prototype属性基础概念
function Person(name, age) {
this.name = name;
this.age = age;
}
// 每个函数都有prototype属性
console.log('Person.prototype:', Person.prototype);
console.log('typeof Person.prototype:', typeof Person.prototype); // "object"
// prototype是一个对象,包含constructor属性
console.log('Person.prototype.constructor:', Person.prototype.constructor);
console.log('Person.prototype.constructor === Person:', Person.prototype.constructor === Person); // true
// 在prototype上添加方法
Person.prototype.greet = function() {
return `Hello, I'm ${this.name}, ${this.age} years old`;
};
Person.prototype.getAge = function() {
return this.age;
};
Person.prototype.setAge = function(newAge) {
if (newAge > 0 && newAge < 150) {
this.age = newAge;
}
};
// 创建实例
const person1 = new Person('Alice', 25);
const person2 = new Person('Bob', 30);
// 实例可以访问原型上的方法
console.log(person1.greet()); // "Hello, I'm Alice, 25 years old"
console.log(person2.greet()); // "Hello, I'm Bob, 30 years old"
// 验证方法来源
console.log('person1.greet === person2.greet:', person1.greet === person2.greet); // true
console.log('person1.hasOwnProperty("greet"):', person1.hasOwnProperty('greet')); // false// 🎉 prototype属性的深入分析
function Animal(species) {
this.species = species;
}
// 原型对象的默认结构
console.log('=== Animal.prototype默认结构 ===');
console.log('Animal.prototype:', Animal.prototype);
console.log('Animal.prototype.constructor:', Animal.prototype.constructor);
console.log('Animal.prototype.__proto__:', Animal.prototype.__proto__);
// 添加原型方法
Animal.prototype.makeSound = function() {
return `${this.species} makes a sound`;
};
Animal.prototype.getInfo = function() {
return `This is a ${this.species}`;
};
// 添加原型属性
Animal.prototype.kingdom = 'Animalia';
Animal.prototype.isAlive = true;
// 创建实例
const dog = new Animal('Dog');
const cat = new Animal('Cat');
console.log('=== 实例访问原型成员 ===');
console.log('dog.makeSound():', dog.makeSound()); // "Dog makes a sound"
console.log('cat.kingdom:', cat.kingdom); // "Animalia"
console.log('dog.isAlive:', dog.isAlive); // true
// 实例属性vs原型属性
dog.isAlive = false; // 在实例上创建同名属性
console.log('dog.isAlive:', dog.isAlive); // false (实例属性)
console.log('cat.isAlive:', cat.isAlive); // true (原型属性)
delete dog.isAlive; // 删除实例属性
console.log('dog.isAlive after delete:', dog.isAlive); // true (回到原型属性)// 🎉 prototype的动态添加和修改
function Calculator() {
this.result = 0;
}
// 初始原型方法
Calculator.prototype.add = function(num) {
this.result += num;
return this;
};
Calculator.prototype.subtract = function(num) {
this.result -= num;
return this;
};
const calc1 = new Calculator();
const calc2 = new Calculator();
// 动态添加原型方法
Calculator.prototype.multiply = function(num) {
this.result *= num;
return this;
};
Calculator.prototype.divide = function(num) {
if (num !== 0) {
this.result /= num;
}
return this;
};
// 已创建的实例也能访问新添加的方法
console.log('=== 动态添加方法测试 ===');
calc1.add(10).multiply(2).subtract(5);
console.log('calc1.result:', calc1.result); // 15
calc2.add(20).divide(4).multiply(3);
console.log('calc2.result:', calc2.result); // 15
// 修改原型方法
const originalAdd = Calculator.prototype.add;
Calculator.prototype.add = function(num) {
console.log(`Adding ${num} to ${this.result}`);
return originalAdd.call(this, num);
};
const calc3 = new Calculator();
calc3.add(5); // "Adding 5 to 0"prototype属性特点:
__proto__属性是每个对象都有的属性,它指向该对象的原型(即创建该对象的构造函数的prototype)。
// 🎉 __proto__属性基础概念
function Vehicle(type) {
this.type = type;
}
Vehicle.prototype.start = function() {
return `${this.type} is starting`;
};
Vehicle.prototype.stop = function() {
return `${this.type} is stopping`;
};
const car = new Vehicle('Car');
// __proto__指向构造函数的prototype
console.log('=== __proto__指向关系 ===');
console.log('car.__proto__ === Vehicle.prototype:', car.__proto__ === Vehicle.prototype); // true
console.log('car.__proto__.constructor === Vehicle:', car.__proto__.constructor === Vehicle); // true
// 通过__proto__访问原型方法
console.log('car.__proto__.start:', car.__proto__.start);
console.log('car.start === car.__proto__.start:', car.start === car.__proto__.start); // true
// __proto__是原型链的关键
console.log('=== 原型链结构 ===');
console.log('car.__proto__:', car.__proto__); // Vehicle.prototype
console.log('car.__proto__.__proto__:', car.__proto__.__proto__); // Object.prototype
console.log('car.__proto__.__proto__.__proto__:', car.__proto__.__proto__.__proto__); // null// 🎉 通过__proto__遍历原型链
function printPrototypeChain(obj, objName = 'obj') {
let current = obj;
let level = 0;
console.log(`=== ${objName}的原型链 ===`);
while (current !== null) {
const indent = ' '.repeat(level);
if (level === 0) {
console.log(`${indent}${objName} (实例对象)`);
console.log(`${indent} - type: ${current.type || 'undefined'}`);
} else {
const constructorName = current.constructor ? current.constructor.name : 'Unknown';
console.log(`${indent}${constructorName}.prototype`);
// 显示原型对象的方法
const methods = Object.getOwnPropertyNames(current)
.filter(name => typeof current[name] === 'function' && name !== 'constructor');
if (methods.length > 0) {
console.log(`${indent} - methods: ${methods.join(', ')}`);
}
}
current = current.__proto__;
level++;
}
console.log(`${indent}null (原型链终点)`);
}
// 创建测试对象
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
return `${this.name} is eating`;
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
// 设置继承关系
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
return `${this.name} is barking`;
};
const myDog = new Dog('Buddy', 'Golden Retriever');
// 遍历原型链
printPrototypeChain(myDog, 'myDog');// 🎉 __proto__的实际应用场景
// 场景1:动态改变对象的原型
const flyingPrototype = {
fly: function() {
return `${this.name} is flying`;
},
land: function() {
return `${this.name} is landing`;
}
};
const swimmingPrototype = {
swim: function() {
return `${this.name} is swimming`;
},
dive: function() {
return `${this.name} is diving`;
}
};
function Bird(name) {
this.name = name;
}
const eagle = new Bird('Eagle');
// 动态改变原型(不推荐在生产环境中使用)
console.log('=== 动态改变原型 ===');
eagle.__proto__ = flyingPrototype;
console.log(eagle.fly()); // "Eagle is flying"
// 场景2:检查原型链
function isInstanceOfCustom(obj, constructor) {
let current = obj.__proto__;
while (current !== null) {
if (current === constructor.prototype) {
return true;
}
current = current.__proto__;
}
return false;
}
// 测试自定义instanceof
console.log('=== 自定义instanceof测试 ===');
console.log('isInstanceOfCustom(myDog, Dog):', isInstanceOfCustom(myDog, Dog)); // true
console.log('isInstanceOfCustom(myDog, Animal):', isInstanceOfCustom(myDog, Animal)); // true
console.log('isInstanceOfCustom(myDog, Object):', isInstanceOfCustom(myDog, Object)); // true
// 场景3:原型链方法查找模拟
function findMethodInPrototypeChain(obj, methodName) {
let current = obj;
let level = 0;
while (current !== null) {
if (current.hasOwnProperty(methodName)) {
return {
found: true,
level: level,
object: current,
method: current[methodName]
};
}
current = current.__proto__;
level++;
}
return { found: false };
}
const result = findMethodInPrototypeChain(myDog, 'bark');
console.log('=== 方法查找结果 ===');
console.log('Method found:', result.found);
console.log('At level:', result.level);
console.log('Method:', result.method);__proto__属性特点:
constructor属性存在于原型对象中,指向创建该原型的构造函数。
// 🎉 constructor属性基础概念
function Book(title, author) {
this.title = title;
this.author = author;
}
Book.prototype.getInfo = function() {
return `"${this.title}" by ${this.author}`;
};
const book1 = new Book('JavaScript Guide', 'John Doe');
// constructor属性的指向关系
console.log('=== constructor属性关系 ===');
console.log('Book.prototype.constructor === Book:', Book.prototype.constructor === Book); // true
console.log('book1.constructor === Book:', book1.constructor === Book); // true
console.log('book1.constructor === book1.__proto__.constructor:', book1.constructor === book1.__proto__.constructor); // true
// 通过constructor创建新实例
const book2 = new book1.constructor('Advanced JavaScript', 'Jane Smith');
console.log('book2.getInfo():', book2.getInfo()); // "Advanced JavaScript" by Jane Smith
// constructor的类型检测作用
console.log('=== constructor类型检测 ===');
console.log('book1.constructor.name:', book1.constructor.name); // "Book"
console.log('book1 instanceof Book:', book1 instanceof Book); // true// 🎉 constructor属性的常见问题
function Student(name, grade) {
this.name = name;
this.grade = grade;
}
// 问题:重写prototype会丢失constructor
console.log('=== 重写prototype前 ===');
console.log('Student.prototype.constructor === Student:', Student.prototype.constructor === Student); // true
// 重写整个prototype对象
Student.prototype = {
study: function() {
return `${this.name} is studying`;
},
getGrade: function() {
return this.grade;
}
};
console.log('=== 重写prototype后 ===');
console.log('Student.prototype.constructor === Student:', Student.prototype.constructor === Student); // false
console.log('Student.prototype.constructor:', Student.prototype.constructor); // Object
const student1 = new Student('Alice', 'A');
console.log('student1.constructor === Student:', student1.constructor === Student); // false
console.log('student1.constructor === Object:', student1.constructor === Object); // true
// 解决方案1:手动恢复constructor
Student.prototype.constructor = Student;
console.log('=== 手动恢复constructor后 ===');
console.log('Student.prototype.constructor === Student:', Student.prototype.constructor === Student); // true
const student2 = new Student('Bob', 'B');
console.log('student2.constructor === Student:', student2.constructor === Student); // true
// 解决方案2:使用Object.defineProperty设置不可枚举的constructor
function Teacher(name, subject) {
this.name = name;
this.subject = subject;
}
Teacher.prototype = {
teach: function() {
return `${this.name} teaches ${this.subject}`;
}
};
// 设置不可枚举的constructor
Object.defineProperty(Teacher.prototype, 'constructor', {
value: Teacher,
writable: true,
configurable: true,
enumerable: false // 不可枚举
});
console.log('=== 不可枚举constructor ===');
console.log('Teacher.prototype.constructor === Teacher:', Teacher.prototype.constructor === Teacher); // true
console.log('Object.keys(Teacher.prototype):', Object.keys(Teacher.prototype)); // ['teach'] (不包含constructor)// 🎉 constructor的实际应用场景
// 场景1:工厂函数中的类型检测
function createInstance(constructor, ...args) {
if (typeof constructor !== 'function') {
throw new Error('Constructor must be a function');
}
const instance = new constructor(...args);
// 验证constructor属性
if (instance.constructor !== constructor) {
console.warn('Constructor property mismatch detected');
}
return instance;
}
// 场景2:对象克隆
function cloneObject(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 使用constructor创建新实例
const clone = new obj.constructor();
// 复制自有属性
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = obj[key];
}
}
return clone;
}
// 测试对象克隆
const originalBook = new Book('Original Title', 'Original Author');
const clonedBook = cloneObject(originalBook);
console.log('=== 对象克隆测试 ===');
console.log('clonedBook.getInfo():', clonedBook.getInfo());
console.log('clonedBook instanceof Book:', clonedBook instanceof Book); // true
console.log('clonedBook !== originalBook:', clonedBook !== originalBook); // true
// 场景3:多态性实现
function Shape() {}
Shape.prototype.area = function() {
throw new Error('area() must be implemented by subclass');
};
function Rectangle(width, height) {
this.width = width;
this.height = height;
}
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
Rectangle.prototype.area = function() {
return this.width * this.height;
};
function Circle(radius) {
this.radius = radius;
}
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
Circle.prototype.area = function() {
return Math.PI * this.radius * this.radius;
};
// 多态性测试
function calculateTotalArea(shapes) {
return shapes.reduce((total, shape) => {
console.log(`Calculating area for ${shape.constructor.name}`);
return total + shape.area();
}, 0);
}
const shapes = [
new Rectangle(5, 10),
new Circle(3),
new Rectangle(8, 6)
];
const totalArea = calculateTotalArea(shapes);
console.log('Total area:', totalArea.toFixed(2));constructor属性特点:
// 🎉 三者关系的完整演示
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hello, I'm ${this.name}`;
};
const person = new Person('Alice');
console.log('=== 三者关系验证 ===');
// 1. 函数的prototype指向原型对象
console.log('Person.prototype是对象:', typeof Person.prototype === 'object'); // true
// 2. 原型对象的constructor指向构造函数
console.log('Person.prototype.constructor === Person:', Person.prototype.constructor === Person); // true
// 3. 实例的__proto__指向构造函数的prototype
console.log('person.__proto__ === Person.prototype:', person.__proto__ === Person.prototype); // true
// 4. 实例的constructor通过原型链指向构造函数
console.log('person.constructor === Person:', person.constructor === Person); // true
// 5. 完整的关系链
console.log('person.constructor === person.__proto__.constructor:', person.constructor === person.__proto__.constructor); // true
console.log('person.__proto__.constructor === Person.prototype.constructor:', person.__proto__.constructor === Person.prototype.constructor); // true
// 关系图文字描述
console.log(`
=== JavaScript原型关系图 ===
Person (构造函数)
↓ .prototype
Person.prototype (原型对象)
↓ .constructor (指回)
Person (构造函数)
person (实例)
↓ .__proto__
Person.prototype (原型对象)
↓ .constructor
Person (构造函数)
总结:
- 构造函数.prototype → 原型对象
- 原型对象.constructor → 构造函数
- 实例.__proto__ → 原型对象
- 实例.constructor → 构造函数 (通过原型链)
`);通过本节JavaScript原型机制详解的学习,你已经掌握:
A: prototype是函数的属性,指向原型对象;__proto__是对象的属性,指向该对象的原型。prototype用于定义原型,__proto__用于访问原型。
A: 因为重写prototype相当于创建了一个新对象,新对象的constructor默认指向Object。需要手动设置constructor属性指向正确的构造函数。
A: __proto__不是正式的ECMAScript标准,但被广泛支持。标准方法是使用Object.getPrototypeOf()和Object.setPrototypeOf()。
A: 使用hasOwnProperty()方法。如果返回true,属性在实例上;如果返回false但能访问到,则在原型链上。
A: 会的。由于原型的动态性,修改原型会立即影响所有通过该原型创建的实例,包括已经创建的实例。
"原型机制是JavaScript的DNA,理解prototype、proto、constructor三者关系,就理解了JavaScript继承的本质!"