JavaScript 是一门基于原型的语言,它的核心概念之一就是原型链。理解原型链是掌握 JavaScript 面向对象编程的关键。本文将通过通俗易懂的方式,带你彻底理解原型链。
1. 什么是原型链?
简单来说,原型链是 JavaScript 中对象之间的一种继承机制。每个对象都有一个隐藏的 __proto__ 属性,指向它的“原型对象”。当你访问一个对象的属性或方法时,如果对象本身没有这个属性,JavaScript 就会沿着 __proto__ 向上查找,直到找到该属性或到达原型链的顶端(null)。
2. 从一个例子开始
我们先来看一个简单的例子:
const animal = {
name: '动物',
eat() {
console.log(this.name + '正在吃东西');
}
};
const dog = {
name: '小狗'
};
// 将 dog 的原型指向 animal
dog.__proto__ = animal;
dog.eat(); // 输出:小狗正在吃东西
发生了什么?
-
dog对象本身没有eat方法。 -
JavaScript 发现
dog.__proto__指向animal,于是去animal中查找eat方法。 -
找到了
eat方法,并调用它。
这就是原型链的基本工作原理!
3. 原型链的结构
为了更好地理解原型链,我们需要了解几个关键概念:
1. __proto__ 属性
-
每个对象都有一个
__proto__属性,指向它的原型对象。 -
例如:
dog.__proto__ === animal。
2. prototype 属性
-
每个函数都有一个
prototype属性(只有函数有)。 -
当你使用
new关键字创建一个对象时,这个对象的__proto__会指向该函数的prototype。
3. constructor 属性
-
每个原型对象都有一个
constructor属性,指向它的构造函数。 -
例如:
animal.constructor === Object。
4. 原型链的尽头
原型链的顶端是 null。当你访问一个属性时,如果沿着原型链一直找不到,最终会到达 null,这时 JavaScript 会返回 undefined。
console.log(dog.toString); // 输出:[Function: toString]
console.log(dog.someNonExistentProperty); // 输出:undefined
5. 构造函数与原型链
当我们使用构造函数创建对象时,原型链的作用更加明显。
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(this.name + '正在吃东西');
};
const dog = new Animal('小狗');
dog.eat(); // 输出:小狗正在吃东西
发生了什么?
-
new Animal('小狗')创建了一个新对象dog。 -
dog.__proto__指向Animal.prototype。 -
Animal.prototype上有eat方法,所以dog可以调用它。
6. 原型链的继承
JavaScript 通过原型链实现继承。例如:
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 的原型为 Animal 的实例
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log(this.name + '在汪汪叫');
};
const myDog = new Dog('小黑', '哈士奇');
myDog.eat(); // 输出:小黑正在吃东西
myDog.bark(); // 输出:小黑在汪汪叫
关键点:
-
Dog.prototype = Object.create(Animal.prototype):将Dog的原型指向Animal的原型。 -
Dog.prototype.constructor = Dog:修复constructor的指向。
7. 总结
-
原型链是 JavaScript 中对象之间继承属性的机制。
-
每个对象都有一个
__proto__属性,指向它的原型对象。 -
每个函数都有一个
prototype属性,用于定义通过该函数创建的对象共享的属性和方法。 -
原型链的顶端是
null。 -
通过原型链,JavaScript 实现了类似传统面向对象语言中的继承。
8. 小练习
-
创建一个
Person构造函数,给它添加一个greet方法。 -
创建一个
Student构造函数,继承Person,并添加一个study方法。 -
创建一个
Student实例,调用greet和study方法。
通过动手实践,你会对原型链有更深的理解!