JavaScript原型、原型链
在 JavaScript 中,原型(Prototype) 和 原型链(Prototype Chain) 是实现继承和共享属性和方法的机制。理解它们是掌握 JavaScript 面向对象编程的关键。
1. 原型(Prototype)
(1) 什么是原型?
- 每个 JavaScript 对象(除
null外)都有一个内部属性[[Prototype]],指向其原型对象。 - 原型对象也是一个普通对象,可以包含属性和方法。
- 通过
__proto__(非标准)或Object.getPrototypeOf()访问原型。
(2) 原型的作用
- 共享属性和方法:所有实例共享原型上的属性和方法,节省内存。
- 实现继承:通过原型链访问父类的属性和方法。
(3) 示例
const person = {
greet() {
console.log(`你好,我是${this.name}`);
}
};
const student = {
name: '张三',
__proto__: person // 设置 student 的原型为 person
};
student.greet(); // 输出:你好,我是张三
2. 原型链(Prototype Chain)
(1) 什么是原型链?
- 当访问对象的属性或方法时,如果对象本身没有,JavaScript 会沿着
[[Prototype]]向上查找,直到找到或到达null。 - 这种链式查找机制称为 原型链。
(2) 原型链的终点
- 所有对象的原型链最终指向
Object.prototype,而Object.prototype的原型是null。
(3) 示例
const animal = {
eat() {
console.log(`${this.name} 正在吃东西`);
}
};
const dog = {
name: '小黑',
__proto__: animal
};
dog.eat(); // 输出:小黑 正在吃东西
console.log(dog.toString()); // 输出:[object Object](来自 Object.prototype)
3. 构造函数与原型
(1) 构造函数的作用
- 构造函数用于创建对象实例。
- 每个构造函数都有一个
prototype属性,指向原型对象。 - 实例的
__proto__指向构造函数的prototype。
(2) 示例
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`你好,我是${this.name}`);
};
const person1 = new Person('李四');
person1.greet(); // 输出:你好,我是李四
console.log(person1.__proto__ === Person.prototype); // true
4. 原型链的继承
(1) 实现继承
- 通过设置子类构造函数的
prototype为父类实例,实现原型链继承。 - 问题:父类实例属性会被所有子类实例共享。
(2) 示例
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(`${this.name} 正在吃东西`);
};
function Dog(name, breed) {
Animal.call(this, name); // 调用父类构造函数
this.breed = breed;
}
// 设置 Dog.prototype 为 Animal 的实例
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复构造函数指向
const dog = new Dog('小黑', '拉布拉多');
dog.eat(); // 输出:小黑 正在吃东西
5. 原型链的查找机制
(1) 查找过程
- 检查对象自身是否有该属性或方法。
- 如果没有,沿着
__proto__查找原型对象。 - 重复步骤 2,直到找到或到达
null。
(2) 示例
const obj = {};
console.log(obj.toString()); // 输出:[object Object]
// 查找过程:obj -> Object.prototype -> null
6. 原型链的注意事项
(1) 原型污染
- 修改原型会影响所有实例。
Array.prototype.push = function() { console.log('原型被修改了!'); }; const arr = [1, 2, 3]; arr.push(4); // 输出:原型被修改了!
(2) 性能问题
- 原型链过长会影响查找性能。
(3) 原型链的终点
- 所有对象的原型链最终指向
Object.prototype,而Object.prototype的原型是null。
7. 原型链的现代替代方案
(1) ES6 类(Class)
- 语法糖,本质仍基于原型链。
- 提供更清晰的继承语法。
class Animal { constructor(name) { this.name = name; } eat() { console.log(`${this.name} 正在吃东西`); } } class Dog extends Animal { constructor(name, breed) { super(name); this.breed = breed; } } const dog = new Dog('小黑', '拉布拉多'); dog.eat(); // 输出:小黑 正在吃东西
(2) Object.create()
- 直接创建对象并指定原型。
const animal = { eat() { console.log(`${this.name} 正在吃东西`); } }; const dog = Object.create(animal); dog.name = '小黑'; dog.eat(); // 输出:小黑 正在吃东西
总结
| 概念 | 描述 | 核心作用 |
|---|---|---|
| 原型 | 对象的[[Prototype]] 属性 | 共享属性和方法 |
| 原型链 | 通过[[Prototype]] 链式查找 | 实现继承和属性查找 |
| 构造函数 | 创建对象实例的函数 | 定义实例属性和原型方法 |
| ES6 类 | 基于原型链的语法糖 | 提供清晰的继承语法 |
理解原型和原型链是掌握 JavaScript 继承机制的基础,同时现代语法(如 class)提供了更简洁的实现方式。
更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github