原型与原型链
外观
原型与原型链[编辑 | 编辑源代码]
原型(Prototype)与原型链(Prototype Chain)是 JavaScript 中实现继承的核心机制,理解它们对于掌握 JavaScript 的面向对象编程至关重要。本文将详细介绍原型、原型链的概念、工作原理及其实际应用。
介绍[编辑 | 编辑源代码]
在 JavaScript 中,每个对象(除了 null
)都有一个与之关联的原型对象(Prototype)。原型对象本身也是一个对象,它包含可以被其他对象继承的属性和方法。当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端(null
)。
原型(Prototype)[编辑 | 编辑源代码]
构造函数的 prototype 属性[编辑 | 编辑源代码]
在 JavaScript 中,每个函数都有一个 prototype
属性(仅函数有),它指向一个对象,该对象是实例对象的原型。
function Person(name) {
this.name = name;
}
// 为 Person 的原型添加方法
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}`);
};
const person1 = new Person("Alice");
person1.sayHello(); // 输出:Hello, my name is Alice
Person.prototype
是person1
的原型对象。person1.__proto__
(非标准属性,但浏览器支持)也指向Person.prototype
。
对象的 __proto__ 属性[编辑 | 编辑源代码]
每个对象都有一个 __proto__
属性(非标准,但广泛支持),指向其构造函数的 prototype
对象。
console.log(person1.__proto__ === Person.prototype); // 输出:true
原型链(Prototype Chain)[编辑 | 编辑源代码]
原型链是由对象的 __proto__
属性串联起来的链式结构。当访问一个对象的属性或方法时,JavaScript 会沿着原型链向上查找。
示例[编辑 | 编辑源代码]
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(`${this.name} is eating.`);
};
function Dog(name, breed) {
Animal.call(this, name); // 调用父类构造函数
this.breed = breed;
}
// 设置 Dog.prototype 的原型为 Animal.prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复 constructor 指向
Dog.prototype.bark = function() {
console.log(`${this.name} is barking!`);
};
const dog1 = new Dog("Buddy", "Golden Retriever");
dog1.eat(); // 输出:Buddy is eating.
dog1.bark(); // 输出:Buddy is barking!
原型链图示[编辑 | 编辑源代码]
dog1.__proto__
指向Dog.prototype
。Dog.prototype.__proto__
指向Animal.prototype
。Animal.prototype.__proto__
指向Object.prototype
。Object.prototype.__proto__
为null
,表示原型链的终点。
实际应用[编辑 | 编辑源代码]
继承的实现[编辑 | 编辑源代码]
原型链是 JavaScript 实现继承的基础。通过修改原型链,可以实现类似传统面向对象语言中的继承。
// 使用 ES6 的 class 语法(底层仍基于原型)
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(`${this.name} is barking!`);
}
}
const dog2 = new Dog("Max", "Labrador");
dog2.eat(); // 输出:Max is eating.
dog2.bark(); // 输出:Max is barking!
内置对象的原型[编辑 | 编辑源代码]
JavaScript 的内置对象(如 Array
、String
)也通过原型链扩展方法。
const arr = [1, 2, 3];
console.log(arr.__proto__ === Array.prototype); // 输出:true
console.log(Array.prototype.__proto__ === Object.prototype); // 输出:true
常见问题[编辑 | 编辑源代码]
如何判断属性是自身的还是继承的?[编辑 | 编辑源代码]
使用 hasOwnProperty
方法:
console.log(dog1.hasOwnProperty("name")); // 输出:true
console.log(dog1.hasOwnProperty("eat")); // 输出:false
如何获取对象的原型?[编辑 | 编辑源代码]
- 非标准方式:
obj.__proto__
- 标准方式:
Object.getPrototypeOf(obj)
console.log(Object.getPrototypeOf(dog1) === Dog.prototype); // 输出:true
总结[编辑 | 编辑源代码]
- 每个对象都有一个原型(
__proto__
),构造函数的prototype
是实例的原型。 - 原型链是对象通过
__proto__
连接起来的链式结构,用于实现属性和方法的继承。 - 原型链的顶端是
Object.prototype
,其__proto__
为null
。 - 实际开发中,可以使用
class
和extends
语法简化继承的实现。