原型(Prototype) 和 原型链(Prototype Chain) 是 JavaScript 中非常重要的概念,它们是 JavaScript 实现继承和共享属性和方法的核心机制。理解原型和原型链可以帮助你更好地掌握 JavaScript 的面向对象编程(OOP)特性。
- 原型(Prototype)
什么是原型?
在 JavaScript 中,每个对象都有一个隐藏的 [[Prototype]] 属性(可以通过 proto 访问),它指向另一个对象,这个对象就是当前对象的 原型。
原型是一个对象,它包含了一些属性和方法,可以被其他对象共享。
原型的作用:
共享属性和方法:通过原型,多个对象可以共享相同的属性和方法,而不需要每个对象都单独定义。
实现继承:原型是 JavaScript 实现继承的基础。
例子:
const person = {
name: "Alice",
greet: function() {
console.log(`Hello, my name is ${this.name}`);
}
};
const student = Object.create(person); // 以 person 为原型创建 student 对象
student.name = "Bob";
student.greet(); // Hello, my name is Bob
解释:
person 是一个普通对象,它有一个 name 属性和一个 greet 方法。
student 对象通过 Object.create(person) 创建,它的原型是 person。
因此,student 可以访问 person 的属性和方法。
- 原型链(Prototype Chain)
什么是原型链?
原型链是由对象的原型组成的链式结构。当访问一个对象的属性或方法时,JavaScript 会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端(null)。
原型链的工作原理:
当访问一个对象的属性或方法时,JavaScript 会先在对象自身查找。
如果找不到,就会去它的原型([[Prototype]])中查找。
如果原型中也没有,就会继续去原型的原型中查找,直到找到或到达 null。
例子:
const animal = {
eat: function() {
console.log("Eating...");
}
};
const dog = Object.create(animal); // dog 的原型是 animal
dog.bark = function() {
console.log("Woof!");
};
const myDog = Object.create(dog); // myDog 的原型是 dog
myDog.name = "Buddy";
myDog.eat(); // Eating...
myDog.bark(); // Woof!
console.log(myDog.name); // Buddy
解释:
myDog 对象自身有 name 属性,所以直接访问 myDog.name。
myDog 没有 eat 方法,所以去它的原型 dog 中查找,dog 也没有 eat 方法,继续去 dog 的原型 animal 中查找,找到了 eat 方法。
myDog 没有 bark 方法,去它的原型 dog 中查找,找到了 bark 方法。
- 构造函数与原型
构造函数:
构造函数是用来创建对象的函数,通常以大写字母开头。
通过 new 关键字调用构造函数时,会创建一个新对象,并将该对象的原型指向构造函数的 prototype 属性。
例子:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
const alice = new Person("Alice");
alice.greet(); // Hello, my name is Alice
解释:
Person 是一个构造函数。
Person.prototype 是 Person 的原型对象,它包含了一个 greet 方法。
通过 new Person("Alice") 创建的对象 alice,它的原型是 Person.prototype,因此可以访问 greet 方法。
- 原型链的顶端
原型链的顶端是 Object.prototype,它是所有对象的最终原型。
Object.prototype 的原型是 null,表示原型链的结束。
例子:
console.log(Object.prototype.__proto__); // null
5. 原型链的应用
(1) 实现继承
通过原型链,可以实现对象之间的继承。
例子:
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 的原型为 Animal 的实例
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复构造函数指向
Dog.prototype.bark = function() {
console.log("Woof!");
};
const myDog = new Dog("Buddy", "Golden Retriever");
myDog.eat(); // Buddy is eating.
myDog.bark(); // Woof!
解释:
Dog
继承了Animal
的属性和方法。Dog.prototype
的原型是Animal.prototype
,因此Dog
的实例可以访问Animal
的方法。
(2) 共享方法
通过原型,可以让多个对象共享相同的方法,节省内存。
例子:
function Car(make, model) {
this.make = make;
this.model = model;
}
Car.prototype.drive = function() {
console.log(`Driving ${this.make} ${this.model}`);
};
const car1 = new Car("Toyota", "Corolla");
const car2 = new Car("Honda", "Civic");
car1.drive(); // Driving Toyota Corolla
car2.drive(); // Driving Honda Civic
解释:
drive 方法定义在 Car.prototype 上,所有 Car 的实例共享这个方法,而不是每个实例都单独定义。
- 总结
概念 描述
原型 每个对象都有一个原型,原型是一个对象,包含共享的属性和方法。
原型链 由对象的原型组成的链式结构,用于查找属性和方法。
构造函数 用于创建对象的函数,通过 new 调用时会创建一个新对象。
继承 通过原型链实现对象之间的继承。
共享方法 将方法定义在原型上,可以让多个对象共享相同的方法,节省内存。
原型和原型链的核心:
原型:每个对象都有一个原型,用于共享属性和方法。
原型链:当访问对象的属性或方法时,JavaScript 会沿着原型链向上查找。
通过理解原型和原型链,你可以更好地掌握 JavaScript 的继承机制和对象模型,写出更高效、更灵活的代码!