一、封装
1. 封装的概念
封装是面向对象编程中的一个重要概念,它将数据(属性)和操作数据的方法封装在一起,形成一个独立的对象。封装的主要目的是隐藏内部实现细节,保护数据的安全性,同时提供一个简洁的外部接口。
2. 封装的重要性
- 对象是一个存储不同属性的容器:对象不仅可以存储数据,还可以通过方法对数据进行操作。
- 确保数据的安全性:直接添加到对象中的属性可以被任意修改,这可能导致数据的不一致性和安全问题。
- 封装的作用:通过封装,可以隐藏内部数据的实现细节,只暴露必要的接口,从而保护数据的安全性。
3. 实现封装的方法
3.1 私有化数据
将需要保护的数据设置为私有,只能在类内部使用。在 JavaScript 中,可以通过 # 前缀来定义私有属性。
3.2 提供 getter 和 setter 方法
通过 getter 和 setter 方法来操作私有属性,可以控制属性的读写权限,并在方法中对属性的值进行验证。
示例代码
class Person {
#name; // 私有属性
constructor(name) {
this.#name = name;
}
// Getter 方法
get name() {
return this.#name;
}
// Setter 方法
set name(value) {
if (typeof value === 'string') {
this.#name = value;
} else {
throw new Error('Name must be a string');
}
}
}
// 使用
const person = new Person("Alice");
console.log(person.name); // 输出: Alice
person.name = "Bob"; // 修改属性
console.log(person.name); // 输出: Bob3.3 封装的好处
- 控制属性的读写权限:通过
getter和setter方法,可以限制属性的访问权限,只允许在满足特定条件时修改属性。 - 数据验证:在
setter方法中可以对属性的值进行验证,确保数据的合法性。 - 隐藏内部实现:将数据和实现细节隐藏在类内部,只暴露必要的接口,减少外部依赖。
4. 封装的实现方式
- 属性私有化:使用
#前缀定义私有属性。 - 通过
getter和setter方法操作属性:javascriptget 属性名() { return this.#属性; } set 属性名(参数) { this.#属性 = 参数; }
通过封装,可以确保数据的安全性,同时提供灵活的接口供外部使用。封装是面向对象编程中的核心概念之一,广泛应用于各种编程语言中。
class Person {
#name;
#age;
getName(){
return this.#name;
}
setName(name){
this.#name = name;
}
getAge(){
return this.#age;
}
setAge(age){
this.#age = age;
}
constructor(name,age){
this.#name = name;
this.#age = age;
}
sayHello(){
console.log(this.#name)
}
}
const p1 = new Person("zs", 18);
console.log(p1);
console.log(p1.getAge());
p1.setAge(11);
console.log(p1.getAge());
p1.sayHello();以下是关于多态的 Markdown 格式内容,优化了排版和结构,使其更加清晰和优美:
二、 多态
多态的概念
多态是面向对象编程中的一个重要概念,允许你通过不同的方式实现相同的行为。它允许一个接口或方法以不同的底层实现来运行,具体实现取决于对象的实际类型。
多态的特点
- 动态类型检查:在 JavaScript 中,不会检查参数的类型,这意味着任何数据都可以作为参数传递。
- 无需指定类型:调用某个函数时,无需指定具体的类型,只要对象满足某些条件即可。
- 鸭子类型:如果一个东西走路像鸭子,叫起来像鸭子,那么它就是鸭子。这种思想体现了多态的核心——关注行为而非类型。
多态的好处
- 灵活性:多态提供了代码的灵活性,允许不同的对象在相同的接口下表现出不同的行为。
- 可扩展性:通过多态,可以轻松地添加新的行为,而无需修改现有的代码结构。
实现多态的方式
在 JavaScript 中,多态通常通过以下方式实现:
1. 方法覆盖(Method Overriding)
通过子类覆盖父类中的方法来实现多态。
示例代码
// 父类
class Animal {
makeSound() {
console.log("Some generic animal sound");
}
}
// 子类
class Dog extends Animal {
makeSound() {
console.log("Woof woof!");
}
}
// 子类
class Cat extends Animal {
makeSound() {
console.log("Meow meow!");
}
}
// 测试
const myDog = new Dog();
const myCat = new Cat();
myDog.makeSound(); // 输出: Woof woof!
myCat.makeSound(); // 输出: Meow meow!2. 参数多态(Parameter Polymorphism)
通过检查参数类型或数量来实现类似多态的行为。
示例代码
function describe(value) {
if (typeof value === "string") {
console.log(`The string is "${value}"`);
} else if (typeof value === "number") {
console.log(`The number is ${value}`);
} else {
console.log("Unknown type");
}
}
// 测试
describe("Hello"); // 输出: The string is "Hello"
describe(42); // 输出: The number is 42
describe(true); // 输出: Unknown type3. 动态类型检查
通过 instanceof 或 typeof 等操作符来检查对象的类型,并根据类型执行不同的逻辑。
示例代码
function processValue(value) {
if (value instanceof Dog) {
value.makeSound(); // 调用 Dog 的 makeSound 方法
} else if (value instanceof Cat) {
value.makeSound(); // 调用 Cat 的 makeSound 方法
} else {
console.log("Unknown type");
}
}
// 测试
processValue(myDog); // 输出: Woof woof!
processValue(myCat); // 输出: Meow meow!总结
多态是面向对象编程中的一个重要概念,允许你通过不同的方式实现相同的行为。在 JavaScript 中,多态通过方法覆盖、参数多态和动态类型检查来实现。多态提供了代码的灵活性和可扩展性,是现代编程中不可或缺的一部分。
通过这些示例和解释,你可以更好地理解和应用多态的概念。
// 父类
class Shape {
draw() {
console.log("Drawing a shape");
}
}
// 子类
class Circle extends Shape {
draw() {
console.log("Drawing a circle");
}
}
// 子类
class Square extends Shape {
draw() {
console.log("Drawing a square");
}
}
// 测试
function drawShape(shape) {
shape.draw();
}
const myCircle = new Circle();
const mySquare = new Square();
drawShape(myCircle); // 输出: Drawing a circle
drawShape(mySquare); // 输出: Drawing a square以下是关于继承的 Markdown 格式内容,优化了排版和结构,使其更加清晰和优美:
三、 继承
继承的概念
继承是面向对象编程中的一个核心概念,允许一个类(称为子类)继承另一个类(称为父类)的属性和方法。通过继承,可以实现代码的复用和扩展。
继承的特点
- 使用
extends关键字:在 JavaScript 中,通过extends关键字实现类的继承。 - 代码复用:当一个类继承另一个类时,子类会自动获得父类的所有属性和方法,就像父类的代码被复制到了子类中一样(简单理解)。
- 父类和子类:在继承关系中,被继承的类称为父类(或超类),继承的类称为子类。
- 扩展性:通过继承,可以在不修改父类的前提下对类的功能进行扩展。
继承的好处
- 减少重复代码:通过继承,可以避免在多个类中重复编写相同的代码。
- 增强可维护性:父类的修改会自动反映到所有子类中,减少了维护成本。
- 提高可扩展性:可以在不修改现有代码的基础上,通过继承添加新的功能。
实现继承的方式
在 JavaScript 中,继承通过 extends 关键字和 super 方法实现。
示例代码
父类
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log(`${this.name} makes a sound.`);
}
}子类
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类的构造函数
this.breed = breed;
}
makeSound() {
console.log(`${this.name} barks.`);
}
displayBreed() {
console.log(`${this.name} is a ${this.breed}.`);
}
}测试
const myDog = new Dog("Buddy", "Golden Retriever");
myDog.makeSound(); // 输出: Buddy barks.
myDog.displayBreed(); // 输出: Buddy is a Golden Retriever.总结
继承是面向对象编程中的一个重要概念,允许一个类继承另一个类的属性和方法。通过继承,可以减少重复代码,增强代码的可维护性和可扩展性。继承、封装和多态是面向对象编程的三大核心特性,它们共同提供了安全性、扩展性和灵活性。
- 封装:关注数据的安全性。
- 继承:关注代码的扩展性。
- 多态:关注行为的灵活性。
通过这些示例和解释,你可以更好地理解和应用继承的概念。
class Animal{
constructor(name){
this.name = name
}
sayHello(){
console.log("动物在叫~")
}
}
class Dog extends Animal{
}
class Cat extends Animal{
}
class Snake extends Animal{
}
const dog = new Dog("旺财")
const cat = new Cat("汤姆")
dog.sayHello()
cat.sayHello()
console.log(dog)
console.log(cat)- 通过继承可以在不修改一个类的情况下对其进行扩展
- OCP 开闭原则
- 程序应该对修改关闭,对扩展开放
class Animal{
constructor(name){
this.name = name
}
sayHello(){
console.log("动物在叫~")
}
}
class Dog extends Animal{
// 在子类中,可以通过创建同名方法来重写父类的方法
sayHello(){
console.log("汪汪汪")
}
}
class Cat extends Animal{
// 重写构造函数
constructor(name, age){
// 重写构造函数时,构造函数的第一行代码必须为super()
super(name) // 调用父类的构造函数
this.age = age
}
sayHello(){
// 调用一下父类的sayHello 如果需要就调用
// super.sayHello() // 在方法中可以使用super来引用父类的方法
console.log("喵喵喵")
}
}
const dog = new Dog("旺财")
const cat = new Cat("汤姆", 3)
dog.sayHello()
cat.sayHello()
console.log(dog)
console.log(cat)