原型链和类继承的区别
1. 原型链(Protrotpye Chain)
核心概念
- 原型(Prototype):每个 JavaScript 对象(除
null
外)都有一个内部属性[[Prototype]]
(可通过__proto__
或Object.getPrototypeOf()
访问),指向它的原型对象。 - 构造函数(Constructor):通过构造函数(普通函数)创建对象时,构造函数的
prototype
属性会成为新对象的原型。 - 原型链:当访问对象的属性或方法时,如果对象本身没有该属性,JavaScript 会沿着原型链(通过
__proto__
)向上查找,直到找到或到达原型链末端(null
)。
示例
javascript
// 构造函数
function Person(name) {
this.name = name;
}
// 在构造函数的原型上添加方法
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}`);
};
// 创建实例
const alice = new Person("Alice");
alice.sayHello(); // 通过原型链找到方法
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
特点
- 显式操作原型:需要手动管理原型链(如
Object.create()
、prototype
属性)。 - 动态性:原型链是动态的,修改原型会立即影响所有实例。
- 灵活性:可以灵活地修改或扩展原型链。
2. 类(Class)
核心概念
- 语法糖:ES6 引入的
class
语法本质上是构造函数和原型链的语法糖,最终仍基于原型链。 - 类声明:通过
class
关键字定义类,包含构造函数(constructor
)、实例方法和静态方法。 - 继承:通过
extends
实现继承,简化了原型链的继承逻辑。
示例
javascript
class Person {
constructor(name) {
this.name = name;
}
// 实例方法(添加到原型)
sayHello() {
console.log(`Hello, I'm ${this.name}`);
}
// 静态方法(直接添加到类本身)
static staticMethod() {
console.log("This is a static method");
}
}
// 继承
class Student extends Person {
constructor(name, grade) {
super(name); // 调用父类构造函数
this.grade = grade;
}
study() {
console.log(`${this.name} is studying`);
}
}
const bob = new Student("Bob", 10);
bob.sayHello(); // 继承自父类原型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
特点
- 语法简洁:隐藏了原型链的复杂性,代码更易读。
- 强制使用
new
:类必须通过new
调用,否则报错。 - 静态方法:通过
static
关键字定义静态方法,直接绑定到类本身。 - 不可枚举:类中定义的方法默认不可枚举(而原型链中手动添加的方法默认可枚举)。
关键区别
特性 | 原型链(Prototype) | 类(Class) |
---|---|---|
语法 | 基于函数和 prototype 属性 | 基于 class 、 constructor 、 extends 等关键字 |
继承实现 | 手动设置 prototype 和 __proto__ | 通过 extends 和 super 自动处理 |
方法定义 | 显式添加到原型(如 Person.prototype.fn ) | 在类内部直接定义(如 method() {} ) |
静态方法 | 手动添加到构造函数(如 Person.staticFn ) | 使用 static 关键字 |
可枚举性 | 默认可枚举 | 默认不可枚举 |
调用限制 | 构造函数可不使用 new (但可能导致问题) | 必须使用 new ,否则报错 |
代码组织 | 松散,依赖约定 | 结构化,更接近传统面向对象语言 |
为什么说类是语法糖?
类的语法底层仍然基于原型链:
javascript
class Person {}
typeof Person; // "function"(类本质是函数)
// 类的原型机制
console.log(Person.prototype.constructor === Person); // true
const alice = new Person();
console.log(alice.__proto__ === Person.prototype); // true
1
2
3
4
5
6
7
2
3
4
5
6
7
总结
- 原型链是 JavaScript 的底层继承机制,灵活但需要手动管理。
- 类是 ES6 引入的语法糖,提供更简洁的语法,但最终仍基于原型链。
- 适用场景:
- 需要底层控制时使用原型链。
- 需要代码可读性和结构化时使用类。
理解原型链是掌握 JavaScript 继承机制的核心,而类的语法让代码更符合现代编程习惯。