重新认识 JS 的类(Class)与构造函数(Constructor)JavaScript 的类和构造函数是面向对象编程
最近在学习手写 Promise 的过程中,我发现自己对 JavaScript 中的类(Class)和构造函数(Constructor)还不是很清楚。因此,今天我决定整理一下这两个概念,并分享我的理解与思考。跟着我的思路,我们一起重新认识一下 JS 中的类、构造函数,以及它们在面向对象编程中的作用。
什么是面向对象编程(OOP)?
面向对象编程(Object-Oriented Programming, OOP) 是一种编程范式,通过对象来组织代码。这些对象代表现实世界中的事务,它们包含属性(状态)和方法(行为)。OOP 的核心思想是将数据和功能封装在对象中,从而提高代码的重用性、可维护性和可扩展性。
在 JavaScript 中,类和构造函数是实现面向对象编程的核心工具。类提供了一种更清晰的语法,而在类出现之前,JavaScript 是通过构造函数来实现类似功能的。
原型与原型链
原型 是 JavaScript 中非常重要的概念。每个对象都有一个原型对象,这个原型为对象提供了共享的属性和方法。原型系统是 JavaScript 实现继承和方法共享的基础。
1. 原型(Prototype)
- 函数原型:每个 JavaScript 函数都有一个
prototype
属性,这是函数创建时自动生成的对象,用于储存可以共享的属性和方法。
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log('Hello, my name is ' + this.name);
};
const person1 = new Person('Alice');
person1.sayHello(); // 输出: Hello, my name is Alice
- 对象原型:每个对象都通过内部属性
__proto__
指向它的原型。
const person1 = new Person('Alice');
console.log(person1.__proto__ === Person.prototype); // 输出: true
2. 原型链(Prototype Chain)
当我们访问一个对象的属性时,JavaScript 会沿着原型链进行查找,直到找到该属性或到达链的顶端(null
)。
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound.`);
};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
console.log(`${this.name} barks.`);
};
const dog = new Dog('Rex');
dog.speak(); // 输出: Rex barks
这里,dog
的原型链如下:
dog ---> Dog.prototype ---> Animal.prototype ---> Object.prototype ---> null
构造函数(Constructor)
在 ES6 之前,JavaScript 没有类的概念,通常通过构造函数来创建对象并定义它们的属性和方法。
- 构造函数 是一种特殊的函数,用于通过
new
关键字创建对象。调用时,它会返回一个新对象,并将this
绑定到该对象上。
function Person(name, age) {
this.name = name;
this.age = age;
}
const person1 = new Person('Alice', 25);
console.log(person1.name); // 输出: Alice
console.log(person1.age); // 输出: 25
在这里,Person
是一个构造函数,而 person1
是 Person
创建的一个实例。
类(Class)
在 ES6 中,JavaScript 引入了 class
语法,提供了一种更直观、更语义化的方式来创建构造函数和处理继承。虽然 class
看起来像其他编程语言中的类,但它其实是语法糖,背后依然依赖于原型机制。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name}.`);
}
}
const person1 = new Person('Alice', 25);
person1.greet(); // 输出: Hello, my name is Alice.
在这个示例中,Person
是一个类,constructor
是其构造函数,用来设置属性。而 greet
方法则是类的实例方法,所有 Person
的实例都可以调用它。
类的继承
class
语法还使得继承更加简单。通过 extends
关键字,我们可以继承父类的属性和方法,同时在子类中进行扩展或重写。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog('Rex');
dog.speak(); // 输出: Rex barks.
在这个例子中,Dog
继承了 Animal
,并且重写了 speak
方法。这样,Dog
的实例将调用子类中的方法,而非父类中的。
总结
JavaScript 的类和构造函数是面向对象编程的核心概念。在 ES6 之前,我们通过构造函数和原型来实现对象创建与继承;而在 ES6 之后,class
为我们提供了一种更加直观的语法,但它本质上仍然依赖于原型机制。理解类和构造函数如何工作,能够帮助我们更好地编写结构化和可扩展的代码。希望通过这篇文章,你能够更好地理解 JavaScript 中类与构造函数的概念,进一步提升对 JS 面向对象编程的掌握。
转载自:https://juejin.cn/post/7426389669526601728