原型继承
在 JavaScript 中,原型继承(Prototype Inheritance)是一种对象通过另一个对象继承属性和方法的机制。JavaScript 是基于原型的语言,这意味着对象可以从其他对象继承属性,而不是通过类继承。下面是关于 JavaScript 原型继承的详细介绍:
1. 什么是原型(Prototype)
在 JavaScript 中,每个对象都有一个关联的内部属性,称为 [[Prototype]]
。这个 [[Prototype]]
是另一个对象,如果在当前对象中没有找到某个属性或方法,JavaScript 会在其 [[Prototype]]
对象中查找。这个链式的继承关系被称为原型链(prototype chain)。
2. 创建对象的原型继承
通过构造函数实现原型继承
// 定义一个构造函数
function Animal(name) {
this.name = name;
}
// 在 Animal 的原型上添加一个方法
Animal.prototype.speak = function() {
console.log(`${this.name} makes a noise.`);
};
// 创建一个新的对象实例
let animal = new Animal('Dog');
animal.speak(); // 输出: Dog makes a noise.
在上面的例子中,Animal
构造函数创建的所有对象都共享 Animal.prototype
上的方法 speak
。如果在对象实例 animal
上找不到 speak
方法,它会在其原型链上查找。
继承另一个对象的属性和方法
// 定义一个构造函数
function Dog(name, breed) {
Animal.call(this, name); // 调用父类构造函数
this.breed = breed;
}
// 设置 Dog 的原型为 Animal 的一个实例
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// 在 Dog 的原型上添加一个方法
Dog.prototype.bark = function() {
console.log(`${this.name} barks.`);
};
let myDog = new Dog('Rex', 'German Shepherd');
myDog.speak(); // 输出: Rex makes a noise.
myDog.bark(); // 输出: Rex barks.
在这个例子中,Dog
继承了 Animal
的属性和方法。Object.create(Animal.prototype)
创建了一个新的对象,这个对象的 [[Prototype]]
指向 Animal.prototype
。因此,Dog.prototype
是 Animal.prototype
的一个实例,Dog
的实例可以访问 Animal
的方法。
3. 使用 Object.create
进行继承
Object.create()
方法可以创建一个新对象,并将其原型设置为指定的对象。
let animal = {
speak: function() {
console.log(`${this.name} makes a noise.`);
}
};
let dog = Object.create(animal);
dog.name = 'Buddy';
dog.speak(); // 输出: Buddy makes a noise.
在这个例子中,dog
对象继承了 animal
对象的 speak
方法。Object.create()
方法为原型继承提供了一种简单而强大的方法。
4. 原型链
JavaScript 中的对象是通过原型链来查找属性的。如果一个对象自身没有某个属性,那么 JavaScript 引擎会沿着原型链向上查找,直到找到该属性或达到链的顶端(通常是 null
)。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
let person1 = new Person('Alice');
let person2 = new Person('Bob');
person1.greet(); // 输出: Hello, my name is Alice
person2.greet(); // 输出: Hello, my name is Bob
console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
在这个例子中:
person1.__proto__
指向Person.prototype
。Person.prototype.__proto__
指向Object.prototype
。
这就是原型链的基本概念。
5. class
语法糖
ES6 引入了 class
语法,这实际上是基于原型的继承的一种语法糖,使得定义和继承类更加直观和简洁。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类的构造函数
this.breed = breed;
}
bark() {
console.log(`${this.name} barks.`);
}
}
let myDog = new Dog('Rex', 'German Shepherd');
myDog.speak(); // 输出: Rex makes a noise.
myDog.bark(); // 输出: Rex barks.
使用 class
和 extends
关键字可以更清晰地表达继承关系,底层仍然是基于原型链的实现。
小结
- JavaScript 的原型继承允许对象从其他对象继承属性和方法。
- 每个对象都有一个
[[Prototype]]
,用来实现属性和方法的继承。 - 可以通过构造函数和
Object.create()
方法来实现原型继承。 - ES6 的
class
语法提供了定义类和继承的简洁方式,但其底层仍然基于原型链。