前端青训营-编程范式

96 阅读11分钟

编程范式

课程收获

  • 了解不同编程范式的起源和适用场景。
  • 掌握JavaScript在不同的编程范式特别是函数式编程范式的使用。
  • 掌握创建领域特定语言的相关工具和模式。

编程语言

机器语言

机器语言是一种由计算机硬件直接识别和执行的低级语言,通常表示为二进制代码。机器语言使用二进制数字序列表示指令和数据,其中每个数字都被称为比特。由于机器语言的指令和数据都是以非常简单的形式直接操作硬件,因此这种编程方式非常有效率,但是它也非常难以阅读和编写。因此,通常会在机器语言之上使用汇编语言或高级语言进行编程。

汇编语言

机器语言是一种由计算机硬件直接识别和执行的低级语言,通常表示为二进制代码。机器语言使用二进制数字序列表示指令和数据,其中每个数字都被称为比特。由于机器语言的指令和数据都是以非常简单的形式直接操作硬件,因此这种编程方式非常有效率,但是它也非常难以阅读和编写。因此,通常会在机器语言之上使用汇编语言或高级语言进行编程。

高级语言

高级语言是一种相对于汇编语言和机器语言而言更为易于理解和编写的编程语言。高级语言中的一条指令可以代表汇编语言或机器语言中的多条指令,使得编写代码更加方便。高级语言通常使用类似于自然语言的语法和结构,程序员可以在开发过程中选择适合自己的编程范式(如面向对象、函数式编程等)来提高程序的可读性和可维护性。

高级语言还提供了丰富的库和框架以简化复杂的编程任务,例如网络编程、界面设计等,并且具有更高的可移植性,因为高级语言的指令并不直接映射到底层的计算机硬件指令,而是由编译器或解释器进行转换和执行,可以使程序在不同的平台上运行。

常见的高级语言包括Java、Python、C++、C#、JavaScript和Swift等。高级语言的缺点是在一定程度上影响了程序的执行效率,有些任务可能需要使用汇编语言或机器语言来实现。

c/c++

C和C++是广泛使用的编程语言,它们都是面向过程和面向对象的编程语言。C语言是一种高效的编程语言,常用于嵌入式系统和操作系统的开发,以及高性能计算方面的应用。相比其他高级语言,C具有更少的语法和更直接的关系到硬件的操作,因此效率非常高。另外,C语言还有广泛的库和工具支持,便于开发者开发高效的和可靠的应用程序。

C++语言则在C语言的基础上添加了面向对象编程的特性,使其更为灵活和模块化。C++常用于开发游戏、图形处理、图像处理、数据库管理等复杂任务,并且可以方便地访问和操作低级和高级硬件资源。C++也可以使用STL(标准模板库)和Boost库等丰富的标准库和开源库。

总体而言,C和C++是底层编程语言,适用于需要高效和直接控制硬件的系统,也适用于需要处理复杂问题和高性能的应用程序开发。但是,因为它们是底层编程语言,所以在编写代码时需要更多的细心和谨慎,避免由于指针和内存管理等问题造成的错误和安全漏洞。

Lisp

 Lisp是一种基于符号表达式的编程语言,被称为“程序员的语言”。Lisp包含许多高级语言所不具备的强大功能,如代码即数据、宏定义、无类型和动态类型等特性。这些特性和支持函数式编程和元编程方面的高级概念,使得Lisp在人工智能研究、自然语言处理、计算机语言处理等领域得到了广泛的应用。

Lisp的一个重要特点是列表结构,而且所有代码和数据都采用列表存储,这使得Lisp在处理递归和数据结构方面非常强大。另外,由于Lisp具有动态类型和高级函数语法,使得Lisp非常适合于解决复杂和动态变化的问题。

Lisp也有很多方言,例如Common Lisp、Scheme和Clojure等,它们都有各自的扩展和特性,适用于不同类型的应用和编程任务。Lisp是一种非常高级的编程语言,对于程序员来说不太友好,但它也提供了一种非常有创造性、灵活的编程方式。

JavaScript

JavaScript是一种面向对象的脚本语言,常见于网页开发中,用于为网页增加交互和动态效果。除此之外,JavaScript也可以在服务器端、桌面应用程序和移动应用程序等多个方面得到应用。

JavaScript的一大优点是它可以在浏览器中直接解释执行,无需安装额外的插件或软件。JavaScript的语法类似于C语言,但也具有很多独特的特性,如动态类型、函数式编程、闭包等,这些特性使得程序员可以更加方便地开发复杂的应用程序。

另外,JavaScript还有很多流行的框架和库,如React、Angular、Vue、jQuery等,它们可以帮助开发者更快地创建高性能和可维护的应用程序。JavaScript的生态系统也非常庞大,有许多社区和开源项目,可以帮助开发者学习和使用JavaScript。

总的来说,JavaScript是一种非常适合于网页开发和交互细节的编程语言,也可以用于开发许多其他类型的应用程序。它有许多强大的功能和库,使得开发人员可以更加轻松和高效地开发出高质量的应用程序。

编程范式

常见编程范式

  • 命令式
    • 面向过程
    • 面向对象
  • 声明式
    • 函数式
    • 响应式

自顶向下

 自顶向下是一种程序设计方法,包括一个逐步推进的过程,从较抽象的应用程序描述,逐步细化为更具体和详细的实现。这种方法从整体到部分地建立程序框架,基于解决问题的想法,以逐层细化细节,直到准备好代码的具体实现。

此方法的优点包括使代码具有良好的设计和模块化,具有良好的可读性、可维护性和可拓展性。同时,它可以在编写代码之前在实践中进行透彻的计划评估,以确保程序的正确性、有效性和可靠性。

通常情况下,自顶向下的过程包括在开发过程中将问题分解为更小的组件,进而细化设计和代码实现的过程。此过程的结果是具有良好设计的程序,这些程序具有结构清晰、代码段易于理解和重复使用的特点。

总之,自顶向下的程序设计方法包括一种相对于底部逐步加紧构建而言更加系统和有序的方式,有助于减轻开发压力和提高生产效率。

结构化编程

结构化编程是一种以顺序、选择和循环等基本结构构建程序,并强调结构清晰、简洁、易于理解和维护的编程方法。这种编程方法通常在面对复杂大型程序时比较有用,因为它可以使程序的组成部分容易管理和修改,从而减轻了程序员的工作量。

结构化编程的核心思想是通过使用模块化编程,将程序分解为较小的、更易于理解和调试的模块。这样一来,程序呈现的是一种自上而下的分解结构,易于理解和修改,并保证了程序更可读性和可维护性。

另外,结构化编程还强调使用控制结构(如if-else条件、循环、跳转和闭合语句)来控制程序流程,以减少程序中的复杂性和混乱。这种详尽的控制结构还允许程序员更轻松地理解代码的执行路径和可能发生的情况,从而减少了程序中的 bug 发生次数。

综上所述,结构化编程是一种面向过程编程方法,是现代计算机编程中最成功、最常用的一种编程范式之一。它提供了有用的技术和工具,有助于程序员构建更有效、更易于理解和维护的程序。

Js的面向过程

//进行导出

//数据
export let car = {
 meter:100,
 speed:10
};

//算法:函数可以看作面向过程中的算法
export function advanceCar(meter){
 while(car < meter){
   car.meter += car.speed;
 }
}

//导入(命名导入),除此之外还有默认导入的方案
import { car , advanceCar } from ".car"//导入上方模块内容

function main(){
  console.log('before',car);
  
  advanceCar(1000)
  
  console.log('after',car)
}

面向过程问题

  • 数据与算法关联弱
  • 不利于修改和扩充
  • 不利于代码重用

面向对象编程

  • 封装
  • 继承
  • 多态
  • 依赖注入

封装

  • 将数据和行为封装在一个对象中,通过访问控制来保护对象的数据和行为,防止外部对象直接访问和修改
  • 封装的目的是隐藏对象的实现细节,提供一个统一的接口来访问对象的数据和行为,增加对象的安全性和可靠性,同时也提高了程序的可维护性和可扩展性
class Person {
  // 姓名、年龄和性别都为private,外部对象无法直接访问和修改
  #name;
  #age;
  #gender;

  constructor(name, age, gender) {
    this.#name = name;
    this.#age = age;
    this.#gender = gender;
  }

  // 公共的getter方法,用于访问和获取私有的数据成员
  getName() {
    return this.#name;
  }

  getAge() {
    return this.#age;
  }

  getGender() {
    return this.#gender;
  }

  // 公共的setter方法,用于修改私有的数据成员
  setName(name) {
    this.#name = name;
  }

  setAge(age) {
    this.#age = age;
  }

  setGender(gender) {
    this.#gender = gender;
  }
}

// 创建一个Person对象,并访问和修改私有的数据成员
const person = new Person('小余', 20, '男');
console.log(person.getName()); // 输出:小余
person.setName('小满');
console.log(person.getName()); // 输出:小满

继承

无需重写的情况下进行功能扩充,这个写法在React中是经常使用的

class Student extends Person {
  #id;
  #score;

  constructor(name, age, gender, id, score) {
    // 调用父类的构造函数,初始化姓名、年龄和性别
    super(name, age, gender);
    this.#id = id;
    this.#score = score;
  }

  // 公共的getter方法,用于访问和获取私有的数据成员
  getId() {
    return this.#id;
  }

  getScore() {
    return this.#score;
  }

  // 公共的setter方法,用于修改私有的数据成员
  setId(id) {
    this.#id = id;
  }

  setScore(score) {
    this.#score = score;
  }
}

// 创建一个Student对象,并访问和修改私有的数据成员
const student = new Student('张三', 20, '男', '1001', 90);
console.log(student.getName()); // 输出:张三
console.log(student.getId()); // 输出:1001
student.setScore(95);
console.log(student.getScore()); // 输出:95

多态

不同的结构可以进行接口共享,进而达到函数复用

  • 基于上面的Person类和Student类,创建了一个printInfo函数,用于打印对象的信息。这个函数接受一个Person或Student对象作为参数,根据对象的类型,打印不同的信息
  • 我们定义了一个printInfo函数,用于打印对象的信息。这个函数接受一个Person或Student对象作为参数,根据对象的类型,打印不同的信息。在函数中,我们使用了instanceof关键字,判断对象的类型,实现了多态
function printInfo(obj) {
  console.log(`姓名:${obj.getName()},年龄:${obj.getAge()},性别:${obj.getGender()}`);
  if (obj instanceof Student) {
    console.log(`学号:${obj.getId()},成绩:${obj.getScore()}`);
  }
}

// 创建一个Person对象和一个Student对象,并分别调用printInfo函数
const person = new Person('张三', 20, '男');
const student = new Student('李四', 22, '女', '1001', 90);

printInfo(person); // 输出:姓名:张三,年龄:20,性别:男
printInfo(student); // 输出:姓名:李四,年龄:22,性别:女,学号:1001,成绩:90

依赖注入

去除代码耦合

  • 依赖注入(Dependency Injection,简称DI)是一种设计模式,它的主要目的是为了解耦合,使得代码更加灵活、可扩展和可维护。在一个应用程序中,各个组件之间通常会存在一些依赖关系,例如一个类需要使用另一个类的对象或者数据。在传统的代码实现中,通常是在类内部创建和管理依赖的对象,这样会导致代码的耦合性很高,一旦依赖的对象发生变化,就需要修改大量的代码,导致代码的可维护性很差。
  • 而依赖注入则是通过将依赖的对象从类内部移动到类的外部,在类的构造函数或者方法中注入依赖的对象。这样做的好处是,使得类与依赖的对象解耦合,使得代码更加灵活、可扩展和可维护。同时,依赖注入也使得代码的测试更加方便,因为测试代码可以注入不同的依赖对象,测试不同的场景和情况。

个人总结

了解不同编程范式的起源和适用场景。掌握 JavaScript 在不同的编程范式特别是函数式编程范式下的使用。进一步掌握创建领域特定语言的相关工具和模式。