第 13 课:原型与继承机制
📌 引言
JavaScript 是一门基于原型的语言,与其他面向对象语言(如 Java、C++)的类继承机制不同。理解 JavaScript 的原型和继承机制是掌握这门语言的关键。原型系统使得对象可以共享属性和方法,同时实现代码复用和继承。
通过本节课的学习,你将掌握:
- JavaScript 原型的概念和工作机制
- 原型链的构成和查找机制
- 构造函数与原型的关系
- ES5 中的继承实现方式
- ES6 class 语法和 extends 关键字
- 原型继承在实际开发中的应用
📚 本节内容概要
✅ 1. 原型基础概念
1.1 什么是原型
在 JavaScript 中,每个对象都有一个内部属性 [[Prototype]](可通过 __proto__ 访问),指向它的原型对象。原型对象也可以有自己的原型,这样就形成了一条原型链。
const obj = {};
console.log(obj.__proto__); // Object.prototype
console.log(obj.__proto__ === Object.prototype); // true
1.2 prototype 属性
只有函数才有 prototype 属性,它指向一个对象,这个对象会成为该函数创建的实例的原型。
function Person() {}
console.log(typeof Person.prototype); // "object"
console.log(Person.prototype.constructor === Person); // true
1.3 __proto__ 与 prototype 的区别
function Animal() {}
const dog = new Animal();
console.log(dog.__proto__ === Animal.prototype); // true
console.log(Animal.__proto__ === Function.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
✅ 2. 原型链机制
2.1 原型链的概念
当访问一个对象的属性时,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或到达原型链的顶端(null)。
function Parent() {
this.parentProp = "父级属性";
}
Parent.prototype.getParentProp = function() {
return this.parentProp;
};
function Child() {
this.childProp = "子级属性";
}
// 建立原型链
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.getChildProp = function() {
return this.childProp;
};
const child = new Child();
console.log(child.getParentProp()); // "父级属性"
console.log(child.getChildProp()); // "子级属性"
2.2 原型链查找过程
const obj = {
a: 1
};
console.log(obj.a); // 1 (自身属性)
console.log(obj.toString); // function toString() (来自 Object.prototype)
// 查找顺序: obj -> obj.__proto__(Object.prototype) -> obj.__proto__.__proto__(null)
✅ 3. 构造函数与原型
3.1 构造函数创建对象
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
return `Hello, I'm ${this.name}`;
};
const person1 = new Person("Alice", 25);
const person2 = new Person("Bob", 30);
console.log(person1.sayHello()); // "Hello, I'm Alice"
console.log(person2.sayHello()); // "Hello, I'm Bob"
console.log(person1.sayHello === person2.sayHello); // true (共享方法)
3.2 instanceof 操作符
console.log(person1 instanceof Person); // true
console.log(Person instanceof Function); // true
console.log(Person instanceof Object); // true
console.log(Function instanceof Object); // true
✅ 4. ES5 继承实现
4.1 原型链继承
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound`);
};
function Dog(name, breed) {
this.name = name;
this.breed = breed;
}
// 继承 Animal
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log(`${this.name} barks`);
};
const dog = new Dog("旺财", "金毛");
dog.speak(); // "旺财 makes a sound"
dog.bark(); // "旺财 barks"
4.2 构造函数继承(借用构造函数)
function Animal(name) {
this.name = name;
this.colors = ["red", "blue"];
}
function Dog(name) {
// 借用父类构造函数
Animal.call(this, name);
}
const dog1 = new Dog("旺财");
const dog2 = new Dog("小黑");
dog1.colors.push("green");
console.log(dog1.colors); // ["red", "blue", "green"]
console.log(dog2.colors); // ["red", "blue"] (不共享引用类型属性)
4.3 组合继承
function Animal(name) {
this.name = name;
this.colors = ["red", "blue"];
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound`);
};
function Dog(name, breed) {
// 继承属性
Animal.call(this, name);
this.breed = breed;
}
// 继承方法
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log(`${this.name} barks`);
};
const dog1 = new Dog("旺财", "金毛");
const dog2 = new Dog("小黑", "哈士奇");
dog1.colors.push("green");
console.log(dog1.colors); // ["red", "blue", "green"]
console.log(dog2.colors); // ["red", "blue"]
✅ 5. ES6 Class 与 extends
5.1 基本 class 语法
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
return `Hello, I'm ${this.name}`;
}
// 静态方法
static getSpecies() {
return "Homo sapiens";
}
}
const person = new Person("Alice", 25);
console.log(person.sayHello()); // "Hello, I'm Alice"
console.log(Person.getSpecies()); // "Homo sapiens"
5.2 extends 实现继承
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
speak() {
super.speak(); // 调用父类方法
console.log(`${this.name} barks`);
}
getInfo() {
return `${this.name} is a ${this.breed}`;
}
}
const dog = new Dog("旺财", "金毛");
dog.speak();
// "旺财 makes a sound"
// "旺财 barks"
console.log(dog.getInfo()); // "旺财 is a 金毛"
5.3 getter 和 setter
class Rectangle {
constructor(width, height) {
this._width = width;
this._height = height;
}
get area() {
return this._width * this._height;
}
set width(value) {
if (value <= 0) {
throw new Error("宽度必须大于0");
}
this._width = value;
}
get width() {
return this._width;
}
}
const rect = new Rectangle(10, 5);
console.log(rect.area); // 50
rect.width = 20;
console.log(rect.area); // 100
🧠 本节重难点分析
🔑 重点内容
| 知识点 | 说明 |
|---|---|
| 原型概念 | 理解 [[Prototype]]、__proto__ 和 prototype 的关系 |
| 原型链 | 掌握属性查找机制 |
| 构造函数 | 理解构造函数如何创建实例 |
| ES6 Class | 掌握 class 语法和 extends 关键字 |
| 继承实现 | 理解不同继承方式的优缺点 |
🧩 难点内容
| 知识点 | 说明 |
|---|---|
| 原型链查找机制 | 理解属性如何沿着原型链查找 |
| 组合继承 | 理解借用构造函数和原型链继承的结合 |
| super 关键字 | 理解在 constructor 和方法中使用 super 的区别 |
| 静态方法与实例方法 | 理解两者的区别和使用场景 |
| 继承中的 this 指向 | 理解继承中 this 的绑定机制 |
📌 第 13 课 10 大高频面试题
1. 什么是原型链?请举例说明。
答案要点:
function Parent() {}
function Child() {}
Child.prototype = new Parent();
const child = new Child();
// child.__proto__ -> Child.prototype -> Parent.prototype -> Object.prototype -> null
2. __proto__ 和 prototype 有什么区别?
答案要点:
prototype是函数的属性,指向原型对象__proto__是对象的属性,指向其原型
3. 如何实现继承?
答案要点:
// ES5 组合继承
function Parent(name) { this.name = name; }
Parent.prototype.sayName = function() { return this.name; };
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
// ES6 Class
class Parent { constructor(name) { this.name = name; } }
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
4. 为什么需要调用 super()?
答案要点:
在子类构造函数中必须先调用 super() 才能使用 this,因为需要先初始化父类的部分。
5. 下面代码输出什么?
function Foo() {}
const f = new Foo();
console.log(f.__proto__ === Foo.prototype);
console.log(Foo.__proto__ === Function.prototype);
答案要点:
都输出 true。
6. 如何判断对象是否具有某个属性?
答案要点:
obj.hasOwnProperty('prop'); // 只检查自身属性
'prop' in obj; // 检查自身和原型链上的属性
7. 什么是静态方法?
答案要点:
属于类本身而不是实例的方法,只能通过类名调用。
class MyClass {
static myStaticMethod() { return "static"; }
}
MyClass.myStaticMethod(); // "static"
8. ES5 和 ES6 继承的区别?
答案要点:
- ES5 通过原型链实现继承
- ES6 使用 class 和 extends 语法糖,更直观
9. getter 和 setter 的作用?
答案要点:
提供对属性访问和设置的控制:
class MyClass {
get prop() { return this._prop; }
set prop(value) { this._prop = value; }
}
10. instanceof 的工作原理?
答案要点:
检查构造函数的 prototype 属性是否出现在实例的原型链上。
🧾 总结
本节课我们深入学习了 JavaScript 的原型系统和继承机制。从原型基础概念到原型链机制,再到 ES5 和 ES6 的继承实现方式,全面掌握了 JavaScript 面向对象编程的核心知识。
通过本节课的学习,你已经具备以下能力:
- 理解原型和原型链的概念及工作机制
- 掌握构造函数创建对象的方法
- 实现 ES5 中的各种继承模式
- 使用 ES6 class 和 extends 语法
- 理解静态方法、getter/setter 的使用
- 解决继承中常见的问题
📅 下一节课安排
第 14 课:ES6+ 新特性
我们将学习 ES6 及后续版本引入的重要新特性,包括 let/const、解构赋值、模板字符串、默认参数、展开运算符、模块化等。这些特性大大提升了 JavaScript 的开发体验和代码质量。
📌 预习建议:
- 了解 ES6 相对于 ES5 的主要改进
- 尝试使用 let 和 const 声明变量
- 查阅 MDN 关于解构赋值的文档

987

被折叠的 条评论
为什么被折叠?



