面向对象编程
JavaScript 中的面向对象编程概念与实现
问题
什么是面向对象编程?JavaScript 如何实现面向对象?
解答
面向对象编程(OOP)是一种以对象为中心的编程范式,通过封装、继承、多态来组织代码。
三大特性
封装:将数据和操作数据的方法绑定在一起,隐藏内部实现。
class User {
#password; // 私有属性
constructor(name, password) {
this.name = name;
this.#password = password;
}
// 公开方法访问私有数据
checkPassword(input) {
return this.#password === input;
}
}
const user = new User("张三", "123456");
console.log(user.name); // "张三"
console.log(user.checkPassword("123456")); // true
// console.log(user.#password); // 报错,无法访问私有属性
继承:子类继承父类的属性和方法。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} 发出声音`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
// 重写父类方法
speak() {
console.log(`${this.name} 汪汪叫`);
}
fetch() {
console.log(`${this.name} 捡球`);
}
}
const dog = new Dog("旺财", "柴犬");
dog.speak(); // "旺财 汪汪叫"
dog.fetch(); // "旺财 捡球"
多态:同一方法在不同对象上有不同表现。
class Shape {
getArea() {
return 0;
}
}
class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
getArea() {
return this.width * this.height;
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
getArea() {
return Math.PI * this.radius ** 2;
}
}
// 同一方法,不同行为
const shapes = [new Rectangle(10, 5), new Circle(7)];
shapes.forEach((shape) => {
console.log(shape.getArea());
});
// 50
// 153.93...
构造函数方式(ES5)
function Person(name, age) {
this.name = name;
this.age = age;
}
// 方法定义在原型上,所有实例共享
Person.prototype.sayHello = function () {
console.log(`我是 ${this.name},今年 ${this.age} 岁`);
};
const p1 = new Person("李四", 25);
const p2 = new Person("王五", 30);
p1.sayHello(); // "我是 李四,今年 25 岁"
console.log(p1.sayHello === p2.sayHello); // true,共享同一方法
原型链继承
function Parent(name) {
this.name = name;
}
Parent.prototype.getName = function () {
return this.name;
};
function Child(name, age) {
Parent.call(this, name); // 继承属性
this.age = age;
}
// 继承方法
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getAge = function () {
return this.age;
};
const child = new Child("小明", 10);
console.log(child.getName()); // "小明"
console.log(child.getAge()); // 10
关键点
- 封装:使用私有属性(
#)隐藏内部实现,通过公开方法暴露接口 - 继承:ES6 用
extends和super,ES5 用Object.create和call - 多态:子类重写父类方法,实现不同行为
- 原型链:JavaScript 通过原型链实现继承,方法定义在
prototype上可被所有实例共享 - class 是语法糖:ES6 的 class 本质上还是基于原型的继承
目录