面向对象 本文包括->面向对象基本概念->三大特性 封装性、继承性、多态性->及涉及的其他概念【要耐心仔细阅读,必有所获!】

一、面向对象的基本概念

1.类(Class)

类是一种抽象的概念,是描述具有相同属性和方法的对象的模板。它定义了一个对象的基本结构和行为

代码如下(示例)

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
  }
}

2.对象(Object)

对象是类的一个实例,具有类定义的属性和方法。在JavaScript中,对象是通过构造函数创建的,使用new关键字实例化类来创建对象。

代码如下(示例)

const person1 = new Person('zhuzhu', 18);

3.实例(Instance)

实例是对象的一种形式化表达,是指从类创建的单个对象。一个类可以有多个实例,每个实例都有自己的属性和方法,但这些属性和方法是从类继承的。

代码如下(示例)

const person2 = new Person('Bob', 30);

4.属性(Property)

属性是对象的特征或数据,描述对象的状态。属性可以是基本数据类型,如数字、字符串、布尔值,也可以是复杂类型,如对象、数组、函数等。

代码如下(示例)

class Person {
  constructor(name, age) {
    this.name = name;  // name属性是一个字符串类型
    this.age = age;    // age属性是一个数字类型
  }
}

5.方法(Method)

方法是与对象关联的函数,用于执行某些特定的操作。方法可以访问和修改对象的属性,也可以返回一个值。

代码如下(示例)

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
  }
}

const person = new Person('Alice', 25);
person.sayHello();  // 输出:Hello, my name is Alice, and I am 25 years old.

6.构造函数(Constructor)

构造函数是用于创建对象的特殊方法。它会在实例化类时自动调用,用于初始化对象的属性和方法。

代码如下(示例)

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
  }
}

7.this关键字

this关键字:this是一个指向当前对象的关键字,用于在类的方法中访问当前对象的属性和方法。

代码如下(示例)

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
  }
}

const person1 = new Person('Alice', 25);
const person2 = new Person('Bob', 30);
person1.sayHello();  // 输出:Hello, my name is Alice, and I am 25 years old

二、封装性

1.访问控制

访问控制指的是对对象属性和方法的访问限制,主要分为公有访问和私有访问。通过封装,我们可以将一些属性和方法设置为私有的,只能在对象内部访问,从而提高数据的安全性和稳定性。而公有访问则是指可以在对象外部访问的属性和方法。

2.私有属性和方法

私有属性和方法指的是只能在对象内部访问的属性和方法,外部无法访问。这些属性和方法一般用于存储对象内部的状态和实现对象的行为。在JavaScript中,可以通过闭包来实现私有属性和方法。

代码如下(示例)

function Person(name, age) {
  // 私有属性
  var gender = 'unknown';

  // 公有属性
  this.name = name;
  this.age = age;

  // 私有方法
  function sayGender() {
    console.log('Gender:', gender);
  }

  // 公有方法
  this.sayName = function() {
    console.log('Name:', this.name);
  };

  // 公有方法访问私有属性和方法
  this.setGender = function(value) {
    gender = value;
    sayGender();
  };
}

var p = new Person('Tom', 20);
p.sayName();  // 输出: Name: Tom
p.setGender('Male');  // 输出: Gender: Male

在这个例子中,gender和sayGender()是私有属性和方法,只能在Person函数内部访问。而name、age、sayName()和setGender()是公有属性和方法,可以在对象外部访问。

3.公有属性和方法

公有属性和方法指的是可以在对象外部访问的属性和方法。一般来说,公有属性和方法都是通过将它们绑定到this上实现的。

代码如下(示例)

function Person(name, age) {
  // 公有属性
  this.name = name;
  this.age = age;

  // 公有方法
  this.sayName = function() {
    console.log('Name:', this.name);
  };
}

var p = new Person('Tom', 20);
console.log(p.name);  // 输出: Tom
p.sayName();  // 输出: Name: Tom

在这个例子中,name、age和sayName()都是公有属性和方法,可以在对象外部访问。

4.getter和setter方法

Getter和Setter方法是一对特殊的函数,它们被用于读取和设置对象的属性值,并且可以在设置属性值时执行一些逻辑操作,从而更好地控制属性的访问。Getter方法用于读取属性值,Setter方法用于设置属性值。在JavaScript中,我们可以通过getter和setter方法来实现属性的封装,控制属性的访问和修改。

代码如下(示例)

class Person {
  constructor(name, age) {
    this._name = name; // 私有属性
    this._age = age; // 私有属性
  }

  get name() { // getter方法
    return this._name;
  }

  set name(name) { // setter方法
    if (typeof name === 'string') {
      this._name = name;
    } else {
      console.log('Error: name must be a string');
    }
  }

  get age() { // getter方法
    return this._age;
  }

  set age(age) { // setter方法
    if (typeof age === 'number' && age > 0) {
      this._age = age;
    } else {
      console.log('Error: age must be a positive number');
    }
  }

  sayHello() { // 公有方法
    console.log(`Hello, my name is ${this._name}, I'm ${this._age} years old.`);
  }
}

const person = new Person('Alice', 20);
person.sayHello(); // 输出: Hello, my name is Alice, I'm 20 years old.

person.name = 'Bob'; // 使用setter方法设置name属性
console.log(person.name); // 使用getter方法读取name属性,输出: Bob

person.age = -10; // 使用setter方法设置age属性,由于年龄不能为负数,会输出Error: age must be a positive number
console.log(person.age); // 输出: 20

在上述示例中,我们使用了构造函数来创建Person类的实例对象,并定义了name和age属性的getter和setter方法。这样就可以在设置属性值时进行类型和范围检查,以确保属性值的有效性和安全性。同时,sayHello方法作为公有方法可以在外部被访问,但是name和age属性由于被封装在了getter和setter方法中,所以只能通过这些方法来访问和修改,从而实现了访问控制


三、继承性

1.继承的基本概念

继承是面向对象编程中的一个核心概念,它允许我们创建一个新类(子类),从已有的类(父类)中继承属性和方法。这意味着,子类可以使用父类中的所有公共方法和属性,而不需要重新编写相同的代码。

2.原型(Prototype)和原型链(Prototype Chain)

原型是 JavaScript 中的一个重要概念,它是一个对象,包含了类中所有实例共享的属性和方法。原型对象被存储在类的 prototype 属性中。通过原型,我们可以实现属性和方法的共享,从而减少重复代码的编写。

原型链是指,每个对象都有一个指向它的原型对象的内部链接,它形成了一个原型链。当我们访问一个对象的属性或方法时,JavaScript 引擎首先在该对象本身查找,如果没有找到,就会继续在原型对象上查找,直到找到该属性或方法为止。

3.原型继承(Prototype Inheritance)

原型继承是通过原型对象实现的继承方式。子类的原型对象被设置为父类的实例,这样就能够继承父类中的所有属性和方法。

代码如下(示例)

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}

function Student(name, age, grade) {
  Person.call(this, name, age);
  this.grade = grade;
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.sayGrade = function() {
  console.log(`I'm in grade ${this.grade}.`);
}

const student = new Student('John', 12, 7);
student.sayHello();
student.sayGrade();

在这个例子中,我们定义了一个 Person 类和一个 Student 类。Person 类有一个 sayHello 方法,Student 类继承了 Person 类,并添加了一个 sayGrade 方法。通过 Object.create() 方法,我们将 Student 类的原型对象设置为一个新的 Person 实例,这样 Student 类就继承了 Person 类中的所有属性和方法。同时,我们使用 call() 方法在 Student 类的构造函数中调用了 Person 类的构造函数,以便在创建 Student 实例时能够初始化 Person 类的属性。

4.类继承(Class Inheritance)

类继承是通过 ES6 中的 class 关键字实现的继承方式。类继承使用 extends 关键字继承父类,可以使用 super 关键字调用父类的构造函数和方法。

代码如下(示例)

class Parent {
  constructor(name) {
    this.name = name;
  }
  
  sayName() {
    console.log(`My name is ${this.name}.`);
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name);
    this.age = age;
  }
  
  sayAge() {
    console.log(`I am ${this.age} years old.`);
  }
}

const child = new Child('Alice', 8);
child.sayName(); // 输出"My name is Alice."
child.sayAge(); // 输出"I am 8 years old."

5.混入(Mixin)

混入(Mixin)是一种将多个对象合并为一个对象的技术。通过混入,可以方便地在不同对象之间共享代码,以实现代码的复用。在JavaScript中,可以通过Object.assign()方法来实现混入。该方法可以将多个对象的属性和方法合并到一个对象中。

代码如下(示例)

let mixin = {
  sayHello() {
    console.log("Hello!");
  },
  sayBye() {
    console.log("Bye!");
  }
};

class Person {
  constructor(name) {
    this.name = name;
  }
}

Object.assign(Person.prototype, mixin);

let person = new Person("John");
person.sayHello(); // 输出 "Hello!"
person.sayBye(); // 输出 "Bye!"

在上面的示例中,我们定义了一个名为mixin的对象,该对象包含了两个方法:sayHello()和sayBye()。然后,我们通过Object.assign()方法将mixin对象的属性和方法复制到Person类的原型中。最后,我们创建了一个Person类的实例,并调用了sayHello()和sayBye()方法,这两个方法是从mixin对象中继承而来的。

提示:通过混入添加的方法,都会被添加到类的原型中,因此它们是公有的。如果要添加私有方法,需要使用其他技术,比如闭包等。

4、多态性

1.多态的基本概念

多态(Polymorphism)是面向对象编程中的一个概念,表示同一种操作或方法可以适用于多个不同的对象或类。它使得我们可以通过一个统一的方式来处理不同的对象或类,使得程序更加灵活、可扩展和易维护。

2.方法的重载(Overloading)

方法的重载(Overloading)是指在同一个类中定义多个同名但参数列表不同的方法,编译器会根据传入的参数类型和数量来确定调用哪一个方法。它可以为程序提供更加灵活的接口,让方法可以接受不同类型的参数。

代码如下(示例)

class Calculator {
  add(a, b) {
    return a + b;
  }

  add(a, b, c) {
    return a + b + c;
  }
}

const calc = new Calculator();

console.log(calc.add(1, 2)); // 输出 3
console.log(calc.add(1, 2, 3)); // 输出 6

3.方法的重写(Overriding)

方法的重写(Overriding)是指在子类中重新定义一个与父类同名的方法,并且参数列表和返回值类型也相同。当通过子类对象调用这个方法时,会优先调用子类中的方法,而不是父类中的方法。它可以让子类覆盖掉父类的方法实现,以实现不同的行为。

代码如下(示例)

class Animal {
  makeSound() {
    console.log('Animal is making sound');
  }
}

class Dog extends Animal {
  makeSound() {
    console.log('Dog is barking');
  }
}

const animal = new Animal();
animal.makeSound(); // 输出 "Animal is making sound"

const dog = new Dog();
dog.makeSound(); // 输出 "Dog is barking"

4.抽象类(Abstract Class)

抽象类(Abstract Class)是一种不能被直接实例化的类,它定义了一些抽象的方法,这些方法必须在子类中被实现。抽象类一般用来定义一些基础的功能和行为,而具体的实现则留给子类来完成。

代码如下(示例)

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }

  // 定义一个抽象方法
  get description() {
    throw new Error('This method must be implemented by the subclass');
  }
}

class Dog extends Animal {
  speak() {
    console.log(`${this.name} barks.`);
  }

  get description() {
    return 'A dog is a kind of animal that likes to bark.';
  }
}

const dog = new Dog('Fido');
dog.speak(); // 输出 "Fido barks."
console.log(dog.description); // 输出 "A dog is a kind of animal that likes to bark."

5.接口(Interface)

接口(Interface)是一种定义对象类型的契约,它定义了对象应该有哪些属性和方法,但并不关心具体的实现。实现了接口的类必须满足接口的所有要求。接口可以为程序提供更加灵活

五、其他概念

1.静态属性和方法

静态属性和方法是指属于类而不是实例的属性和方法,可以直接通过类访问而不需要实例化。在JavaScript中,可以使用静态关键字static来定义静态属性和方法。

代码如下(示例)

class Circle {
  static PI = 3.1415; // 静态属性

  static calculateArea(radius) { // 静态方法
    return Circle.PI * radius * radius;
  }
}

console.log(Circle.PI); // 3.1415
console.log(Circle.calculateArea(5)); // 78.5375

2.闭包(Closure)

闭包指的是一个函数内部的局部变量,因为被其它函数引用而被保存起来的特殊状态。JavaScript 中的闭包是一种强大而又神秘的特性,可以将函数和其所操作的变量绑定在一起。

代码如下(示例)

function counter() {
  let count = 0;
  return function () {
    return ++count;
  }
}

const increment = counter();
console.log(increment()); // 输出 1
console.log(increment()); // 输出 2
console.log(increment()); // 输出 3

3.单例模式(Singleton Pattern)

单例模式是一种创建型设计模式,确保类只有一个实例,并提供全局访问点。在 JavaScript 中,可以通过构造函数或者对象字面量来实现单例模式。

代码如下(示例)

//使用构造函数实现单例模式
function AppConfig() {
  if (AppConfig.instance) {
    return AppConfig.instance;
  }
  AppConfig.instance = this;
  this.apiKey = 'my-api-key';
  this.apiUrl = 'https://api.example.com';
}

const appConfig1 = new AppConfig();
const appConfig2 = new AppConfig();

console.log(appConfig1 === appConfig2); // 输出 true

4.工厂模式(Factory Pattern)

工厂模式是一种创建型设计模式,通过创建工厂函数,将对象的创建过程封装起来,使其更具有可复用性和扩展性。

代码如下(示例)

class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  speak() {
    console.log(`${this.name} is speaking.`);
  }
}

class Dog extends Animal {
  constructor(name, age, breed) {
    super(name, age);
    this.breed = breed;
  }

  speak() {
    console.log(`${this.name} is barking.`);
  }
}

class Cat extends Animal {
  constructor(name, age, color) {
    super(name, age);
    this.color = color;
  }

  speak() {
    console.log(`${this.name} is meowing.`);
  }
}

function animalFactory(type, ...args) {
  switch (type) {
    case 'dog':
      return new Dog(...args);
    case 'cat':
      return new Cat(...args);
    default:
      throw new Error('Invalid animal type.');
  }
}

const dog = animalFactory('dog', 'Max', 3, 'Golden Retriever');
const cat = animalFactory('cat', 'Mimi', 2, 'Black');

dog.speak(); // 输出 "Max is barking."
cat.speak(); // 输出 "Mimi is meowing."

5.观察者模式(Observer Pattern)

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖者都会收到通知并更新。

代码如下(示例)

class Subject {
  constructor() {
    this.observers = [];
  }

  attach(observer) {
    this.observers.push(observer);
  }

  detach(observer) {
    const index = this.observers.indexOf(observer);
    if (index !== -1) {
      this.observers.splice(index, 1);
    }
  }

  notify() {
    for (const observer of this.observers) {
      observer.update(this);
    }
  }
}

class ConcreteSubject extends Subject {
  constructor() {
    super();
    this.state = null;
  }

  getState() {
    return this.state;
  }

  setState(state) {
    this.state = state;
    this.notify();
  }
}

class Observer {
  update() {
    // 默认行为为空
  }
}

class ConcreteObserver extends Observer {
  update(subject) {
    console.log(`The subject's state has changed to: ${subject.getState()}`);
  }
}

const subject = new ConcreteSubject();
const observer1 = new ConcreteObserver();
const observer2 = new ConcreteObserver();

subject.attach(observer1);
subject.attach(observer2);

subject.setState("new state"); // 输出: "The subject's state has changed to: new state"

这个观察者模式示例,其中 Subject 对象维护其依赖项列表,并提供 attach 和 detach 方法,以便观察者可以注册或取消注册

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值