课程布景:

  1. 前端的首要编程言语为JavaScript.
  2. JavaScript做为一种融合了多种编程范式的言语,灵敏性十分高。
  3. 前端开发人员需求依据场景在不同编程范式间自如切换。
  4. 进一步需求发明范畴特定言语笼统业务问题。

课程收益:

  1. 了解不同编程范式的起源和适用场景。
  2. 把握JavaScript在不同的编程范式特别是函数式编程范式的运用。
  3. 把握创立范畴特定言语的相关东西和办法。

PS:课程讲师的气泡音实在太刺耳清楚了,学习得花一半的心思去留意他讲了什么。学习很难进入沉溺状况

编程言语

机器言语

第一代核算机(1940年代末至1950年代初):第一代核算机运用的是机器言语,这种言语是二进制的,十分难以阅览和编写

编程范式(万字笔记) | 青训营笔记

  • 乃至一开始他是经过线缆来操控的

编程范式(万字笔记) | 青训营笔记

汇编言语

汇编言语(1950年代中期):为了使程序员能够更简略地编写代码,汇编言语被发明晰出来。汇编言语是一种更高等级的机器言语,运用助记符来代替二进制代码,使程序员能够更简略地编写和阅览代码

编程范式(万字笔记) | 青训营笔记

中级言语

中级言语是介于机器言语和高档言语之间的一种言语。它一般是一种可移植的高档言语,但在执行时被转换成机器言语。中级言语具有比高档言语更挨近机器言语的特色,因而它们一般比高档言语更快,但比机器言语和汇编言语更易读和编写。一些常见的中级言语包含C言语和C++言语

C:”中级言语”进程式言语代表

  • 可对位,字节,地址直接操作

    • 代码中的*(&x) = 20;语句能够直接修正变量x的值,阐明C言语能够对位、字节、地址进行直接操作
  • 代码和数据别离倡导结构化编程

    • 代码中的#include <stdio.h>语句引进了规范输入输出库,阐明C言语倡导代码和数据别离,支撑结构化编程
  • 功用齐全:数据类型和操控逻辑多样化

    • 代码中声明晰整型变量x和字符指针变量str,运用了printf函数进行输出,阐明C言语的数据类型和操控逻辑十分多样化,功用齐全
  • 可移植能力强

    • 代码中运用了规范输入输出库,这使得代码能够在不同的平台上运转,阐明C言语具有很强的可移植能力
#include <stdio.h> // 引进规范输入输出库int main() // 主函数
{
  int x = 10; // 声明并初始化一个整型变量x
  char* str = "Hello, World!"; // 声明并初始化一个指向字符的指针变量strprintf("x = %d\n", x); // 输出x的值
  printf("str = %s\n", str); // 输出str所指向的字符串
​
  *(&x) = 20; // 对x的值进行修正,阐明C言语能够对位、字节、地址进行直接操作
  printf("x = %d\n", x); // 输出修正后的x的值return 0; // 回来0表明程序正常完毕,阐明C言语支撑函数回来值
}

C++:面向目标言语代表

  • C with Classes

    • C++开始是作为C言语的一种扩展,其基本语法与C言语相同,但增加了类、承继、多态等面向目标的特性,因而C++也被称为C with Classes
  • 承继

    • 代码中的class Student : public Person语句界说了一个Student类,它承继自Person类,这阐明C++支撑承继的特性
  • 权限操控

    • 代码中的publicprotectedprivate关键字用来操控成员变量和成员函数的拜访权限,这阐明C++支撑权限操控的特性
  • 虚函数

    • 代码中的virtual void sayHello()语句界说了一个虚函数,这阐明C++支撑虚函数的特性。虚函数能够完成多态,即在运转时依据目标的实践类型来调用相应的函数
  • 多态

    • 代码中的void sayHello() override语句完成了函数的重写,这阐明C++支撑多态的特性。在运转时,假如调用的函数是虚函数,那么实践调用的函数将依据目标的实践类型来确认
#include <iostream> // 引进输入输出库// 界说一个类Person
class Person {
public: // 公有权限
  // 结构函数
  Person(std::string name, int age) : mName(name), mAge(age) {}
​
  // 成员函数
  virtual void sayHello() { // 界说虚函数,支撑多态
    std::cout << "Hello, I'm " << mName << ", " << mAge << " years old." << std::endl;
   }
​
protected: // 保护权限
  std::string mName; // 名字
  int mAge; // 年纪
};
​
// 界说一个类Student,承继自Person
class Student : public Person {
public: // 公有权限
  // 结构函数
  Student(std::string name, int age, std::string school) : Person(name, age), mSchool(school) {}
​
  // 重写父类的虚函数
  void sayHello() override { // 界说虚函数,支撑多态
    std::cout << "Hello, I'm " << mName << ", " << mAge << " years old, and I'm studying at " << mSchool << "." << std::endl;
   }
​
private: // 私有权限
  std::string mSchool; // 校园
};
​
int main() {
  // 创立一个Person目标
  Person person("Tom", 20);
  person.sayHello(); // 调用Person的sayHello函数// 创立一个Student目标
  Student student("Jerry", 18, "ABC University");
  student.sayHello(); // 调用Student的sayHello函数,完成多态return 0; // 回来0表明程序正常完毕
}

Lisp:函数式言语代表

  • 与机器无关
  • 列表:代码即数据
  • 闭包
(setq nums `(1 2 3 4)); 数据列表
​
(setq add `+) ;加操作
​
(defun run(op exp) (eval (cons op exp)) ) ;将数据构建为代码列表  连接列表
​
(run add nums) ;运转

JavaScript

  • 依据原型和头等函数的多范式言语

    • 进程式

      • JavaScript开始被规划为一种进程式的脚本言语,它能够在Web浏览器中嵌入HTML页面,完成动态交互效果
    • 面向目标

      • JavaScript是一种支撑面向目标编程的言语,它支撑类、目标、承继、封装等面向目标的特性。JavaScript中的目标是动态的,能够随时增加或删去属性和办法
    • 函数式

      • JavaScript是一种支撑函数式编程的言语,它的函数能够作为一等公民,能够赋值给变量,能够作为参数传递给其他函数,能够作为回来值回来给其他函数
    • 呼应式

      • JavaScript能够经过DOM操作完成呼应式编程,能够完成页面元素的动态更新,与用户的交互效果等

除了上述视频中说到的这几点,还有额外的特色进行弥补:

  • 弱类型:JavaScript是一种弱类型的言语,不需求事先声明变量的类型,变量的类型会在运转时主动揣度(在TS中变成强类型)。
  • 解说性:JavaScript是一种解说性的言语,不需求编译成可执行文件,能够直接在浏览器中执行(经典的例如V8引擎会进行处理)。
  • 高阶函数:JavaScript中的函数能够作为参数传递给其他函数,也能够作为回来值回来给其他函数,这种函数称为高阶函数。
  • 闭包:JavaScript中的函数能够构成闭包,即在函数内部界说的变量能够在函数外部拜访,这种特性能够完成私有变量和函数的封装。

高档言语

高档言语是一种人类易于了解和运用的核算机言语。它运用自然言语的办法来描述问题,而不是运用机器言语或汇编言语。高档言语一般具有较高的可读性和可保护性,使程序员能够更简略地编写和修正代码。一些常见的高档言语包含Java、Python和JavaScript等

编程范式(万字笔记) | 青训营笔记

思维导图总结

编程范式(万字笔记) | 青训营笔记

编程范式

程序言语特性

  1. 是否允许副效果
  2. 操作的执行次序
  3. 代码安排
  4. 状况办理
  5. 语法和词法

编程范式

  • 指令式:指令式编程是一种以核算机执行的指令为中心的编程范式,它首要分为面向进程和面向目标两种办法

    1. 面向进程

      • 面向进程是一种以进程为中心的编程办法,它将问题分解为一系列进程,经过函数的调用来完成程序的功用。面向进程的代码一般是一系列的指令,描述了核算机执行的详细进程
    2. 面向目标

      • 面向目标是一种以目标为中心的编程办法,它将数据和函数封装在一同,经过目标的交互来完成程序的功用。面向目标的代码一般是一系列的目标,描述了程序中的实体和它们之间的联系
  • 声明式:声明式编程是一种以描述问题为中心的编程范式,它首要分为函数式和呼应式两种办法

    1. 函数式

      • 函数式编程是一种以函数为中心的编程办法,它将核算视为函数的运用,经过函数的组合来完成程序的功用。函数式的代码一般是一系列的函数调用,描述了核算的进程
    2. 呼应式

      • 呼应式编程是一种以数据流为中心的编程办法,它将数据和函数封装在一同,经过数据的改变来触发函数的执行,完成程序的功用。呼应式的代码一般是一系列的数据流,描述了数据的改变和处理

进程式

自顶向下

编程范式(万字笔记) | 青训营笔记

调用的进程

编程范式(万字笔记) | 青训营笔记

结构化编程

结构化编程是一种以结构为中心的编程范式,它首要重视程序的可读性、可保护性和可扩展性,经过一系列的结构化的操控流程来安排程序的逻辑。

结构化编程的首要特色是:

  1. 次序结构:程序按照次序执行,从上到下依次执行每一条语句。
  2. 挑选结构:程序依据条件挑选执行不同的语句,包含if语句、switch语句等。
  3. 循环结构:程序经过循环执行一组语句,包含for、while、do-while等循环语句。

结构化编程的长处在于:

  1. 代码明晰:结构化编程经过一系列的结构化操控流程来安排程序的逻辑,使得代码愈加明晰易懂。
  2. 可保护性高:结构化编程使得代码的逻辑愈加明晰,易于保护和修正。
  3. 可扩展性强:结构化编程使得程序的逻辑愈加明晰,易于扩展和增加新的功用。

结构化编程是现代编程言语的根底,几乎一切的编程言语都支撑结构化编程。结构化编程的思想也是面向目标编程、函数式编程等其他编程范式的根底。

编程范式(万字笔记) | 青训营笔记

上图中左面是不和案例,右边是正确示例

JS中的面向进程

下方中完毕的;归于可加可不加的,但详细的规矩如下:

  1. 行完毕:当一行代码完毕时,假如下一行代码不是有效的JavaScript代码(比方空行或注释),JavaScript解析器会主动插入分号。
  2. 语句块完毕:当一段代码块完毕时,假如下一行代码不是有效的JavaScript代码,JavaScript解析器会主动插入分号。
  3. return语句:在return语句后边的表达式假如不是一行代码的最初,JavaScript解析器会主动插入分号。
  4. break语句和continue语句:在break语句和continue语句后边假如不是一行代码的最初,JavaScript解析器会主动插入分号。
//进行导出//数据
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)
}
  • 模块化的计划不止ES6中的import导入export导出计划。在ES6正式出来之前,社区也有自己依据需求编写了其他的计划,目前还在流行的有CommonJS计划
  • ES6的模块化计划和CommonJS都是JavaScript中常见的模块化计划,它们都支撑导入和导出模块的功用,但是在详细的语法和运用办法上有所不同。ES6运用import和export关键字来导入和导出模块,而CommonJS运用require和module.exports来导入和导出模块。ES6的导入和导出是静态的,不能在运转时动态导入和导出,而CommonJS的导入和导出是动态的,能够在运转时动态地导入和导出模块
// 导出
module.exports = {
 a: 1,
 foo: function() {},
 MyClass: class {}
};
// 导入
const { a, foo, MyClass } = require('./module.js');

面向进程式编程有什么缺点?为什么后边会出现面向目标

  • 数据与算法相关弱

  • 不利于修正和扩大

    • 可保护性差:面向进程式编程缺少封装性和笼统性,代码的耦合度高,修正代码时简略影响其他部分的代码,导致保护性差
  • 不利于代码重用

    • 可扩展性差:面向进程式编程很难对程序进行扩展,因为程序的逻辑分散在各个函数或进程中,很难进行整体性的扩展

面向目标的出现处理了这几个问题

  • 可读性好:面向目标编程将数据和函数封装在一同,代码的可读性好,易于了解整个程序的逻辑。
  • 可保护性好:面向目标编程具有封装性和笼统性,代码的耦合度低,修正代码时只需求修正目标的内部完成,不会影响其他部分的代码,导致保护性好。
  • 可扩展性好:面向目标编程将数据和函数封装在一同,目标之间经过接口进行交互,易于对程序进行扩展。

面向目标

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

封装

  • 将数据和行为封装在一个目标中,经过拜访操控来保护目标的数据和行为,防止外部目标直接拜访和修正
  • 封装的意图是躲藏目标的完成细节,供给一个统一的接口来拜访目标的数据和行为,增加目标的安全性和可靠性,一同也进步了程序的可保护性和可扩展性
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)是一种规划办法,它的首要意图是为了解耦合,使得代码愈加灵敏、可扩展和可保护。在一个运用程序中,各个组件之间一般会存在一些依靠联系,例如一个类需求运用另一个类的目标或许数据。在传统的代码完成中,一般是在类内部创立和办理依靠的目标,这样会导致代码的耦合性很高,一旦依靠的目标发生改变,就需求修正很多的代码,导致代码的可保护性很差。
  • 而依靠注入则是经过将依靠的目标从类内部移动到类的外部,在类的结构函数或许办法中注入依靠的目标。这样做的好处是,使得类与依靠的目标解耦合,使得代码愈加灵敏、可扩展和可保护。一同,依靠注入也使得代码的测验愈加方便,因为测验代码能够注入不同的依靠目标,测验不同的场景和状况。

编程范式(万字笔记) | 青训营笔记

面向目标编程_五大准则

  • 单一责任准则SRP(Single Responsibility Principle)

    • 一个类只负责一个功用范畴中的相应责任,或许能够界说为一个类只有一个引起它改变的原因。这个准则的意图是将责任别离,进步类的内聚性,下降类的耦合性,使得代码愈加灵敏、可保护和可扩展
  • 敞开封闭准则OCP(Open-Close Principle)

    • 一个软件实体(类、模块、函数等)应该对扩展敞开,对修正封闭。这个准则的意图是使得代码愈加灵敏、可扩展和可保护,一同也能下降代码的风险和复杂度。经过运用笼统化和多态等技术,使得代码能够习惯不同的需求和改变
  • 里式替换准则LSP(the Liskov Substitution Principle LSP)

    • 一切引证基类(父类)的地方有必要能透明地运用其子类的目标。这个准则的意图是保证代码的正确性和可靠性,防止在子类中破坏父类的行为和逻辑。经过遵循这个准则,能够使得代码愈加灵敏、可扩展和可保护
  • 依靠倒置准则DIP(the Dependency Inversion Principle DIP)

    • 高层模块不应该依靠于底层模块,两者都应该依靠于笼统;笼统不应该依靠于详细完成,详细完成应该依靠于笼统。这个准则的意图是下降代码的耦合性,进步代码的灵敏性和可扩展性。经过运用接口和笼统类等技术,使得代码能够习惯不同的需求和改变
  • 接口别离准则ISP(the Interface Segregation Principle ISP)

    • 一个类不应该依靠于它不需求的接口,一个类应该只依靠于它需求的接口。这个准则的意图是下降代码的耦合性,进步代码的灵敏性和可扩展性。经过将接口进行别离,使得代码愈加灵敏、可保护和可扩展

面向目标编程有什么缺点?为什么咱们推荐函数式编程

编程范式(万字笔记) | 青训营笔记

函数式编程

函数的特色

  • 函数是”一等公民”
  • 纯函数/无副效果
  • 高阶函数跟闭包

编程范式(万字笔记) | 青训营笔记

优势

经过一节课很难深入领会到他的好处,需求额外的拓展学习

  1. 可缓存
  2. 可移植
  3. 可测验
  4. 可推理
  5. 可并行
//代码1
const retireAge = 100
​
function retirePerson(p){
 if(p.age > retireAge){
  p.status = "retired"
  }
}
//代码2
function retirePerson(p){
 const retireAge = 100
  if(p.age > retireAge){
    return {
    ...p,
    status = "retired"
   }
  }
 return p
}

经过上述两段代码,能够看出代码二的如下优势:

  1. 增加了代码的可测验性:因为代码2中的函数回来了一个新目标,而不是直接修正原目标,因而能够更方便地进行单元测验,防止了测验进程中修正原目标的副效果。
  2. 增加了代码的可保护性:因为代码2中的函数不直接修正原目标(在React中这个称之为不可变的力量),而是回来一个新目标,因而更简略保护和修正。假如要修正函数的行为,只需求修正函数内部的代码即可,不会对其他代码产生影响。
  3. 增加了代码的可读性:因为代码2中的函数回来了一个新目标,而不是直接修正原目标,因而代码的含义愈加明晰明确。一同,代码2中的函数运用了解构赋值和目标展开运算符,使得代码愈加简洁、易读。

柯里化函数

这里我就搬我以前的笔记了

  • 柯里化也是归于函数式编程里边一个十分重要的概念

  • 维基百科解说:

    • 在核算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化
    • 是把接纳多个参数的函数,变成承受一个单一参数(开始函数的第一个参数)的函数,并且回来承受余下的参数,而且回来成果的新函数的技术
    • 柯里化声称”假如你固定某些参数,你将得到承受余下参数的一个函数
  • 柯里化总结

    • 只传递给函数一部分参数来调用它,让它回来另一个函数处理剩下的参数
    • 这个进程称为柯里化
//假设咱们有一个需求填入4个参数的 函数
function foo(m,n,x,y){
  
}
foo(10,20,30,40)
//柯里化的进程
//咱们对其进行转化,变得只需求传入一个参数,但这里边需求回来一个函数持续处理剩下的参数
function bar(m){
  return function(n){
    return function(x,y){
      //你也能够将y参数持续return
      m+n+x+y
     }
   }
}
bar(10)(20)(30,40)
柯里化的结构
//正常结构
function add(x,y,z){
  return x+y+z
}
​
var result = add(10,20,30)
console.log(result);
​
//柯里化
function sum(x){
  return function(y){
    return function(z){
      return x+y+z
     }
   }
}
​
var result1 = sum(10)(20)(30)
console.log(result1);
​
//简化柯里化代码
var sum2 = x=>y=>z=>{
  return x+y+z 
}
//还能再次简化var sum2 = x=>y=>z=>x+y+z
var result2 = sum2(20)(30)(40)
console.log(result2,"运用箭头函数简化柯里化的办法")
柯里化的效果
  • 那么为什么需求有柯里化呢?

    • 在函数式编程中,咱们其实往往希望一个函数处理的问题尽可能的单一,而不是将一大堆的处理进程交给一个函数来处理
    • 那么咱们是否就能够将每次传入的参数在单一的函数中进行处理,处理完后在下一个函数中再运用处理后的成果
单一责任准则(SRP)
面向目标 ->-> 尽量只完成一件单一的作业
柯里化 – 单一责任的准则
//悉数挤在一同处理
function add(x,y,z){
  x = x + 2
  y = y * 2
  z = z * z
  return x + y +z
}
​
console.log(add(10,20,30));
//柯里化处理
function sum(x){
  x = x + 2
  return function(y){
    y = y * 2
    return function(z){
      z = z * z
        return x + y + z
     }
   }
}
console.log(sum(10)(20)(30));
柯里化案例

只举例一个,否则内容过多

//打印日志时刻
function log(date,type,message){
  console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]:[${message}]`)
}
log(new Date(),'DEBUG','查找到轮播图的bug')//[22:24][DEBUG]:[查找到轮播图的bug]
log(new Date(),'DEBUG','查询菜单的bug')//[22:24][DEBUG]:[查询菜单的bug]
log(new Date(),'DEBUG','查询数据的bug')//[22:24][DEBUG]:[查询数据的bug]
---------------------------------------------------------------------------------------------
//柯里化优化
var log = date => type => message =>{
  console.log(`[${date.getHours()}:${date.getMinutes()}][${type}]:[${message}]`)
}
//假如我打印的都是当前的时刻,咱们就能够将时刻复用
var nowLog = log(new Date());
nowLog("DEBUG")("查找小满去哪了")//[22:32][DEBUG]:[查找小满去哪了]
//或许时刻+类型都悉数复用
var nowLog1 = log(new Date())("小满系列查找");
nowLog1("查找小满人去哪了")//[22:34][小满系列查找]:[查找小满人去哪了]
nowLog1("查找小满的黑丝去哪了")//[22:34][小满系列查找]:[查找小满的黑丝去哪了]
nowLog1("查找小满的裤衩子被谁拿走了")//[22:34][小满系列查找]:[查找小满的裤衩子被谁拿走了]
nowLog1("查找小满有没有去按摩店找小姐姐")//[22:34][小满系列查找]:[查找小满有没有去按摩店找小姐姐]

组合函数

组合(Compose)函数是在JavaScript开发进程中一种对函数的运用技巧、办法:

  • 比方咱们现在需求对某一个数据进行函数的调用,执行两个函数fn1和fn2,这两个函数是依次执行的;
  • 那么假如每次咱们都需求进行两个函数的调用,操作上就会显得重复
  • 那么是否能够将这两个函数组合起来,主动依次调用呢?
  • 这个进程便是对函数的组合,咱们称之为 组合函数(Compose Function);
function double(num){
  return num*2
}
​
function square(num){
  return num ** 2//平方
}
​
var count = 10
var result = square(double(count))
console.log(result);
​
//如何将double和square结合起来,完成简略的组合函数
function composeFn(m,n){
  return function(count){
    return n(m(count))
   }
}
​
var newFn = composeFn(double,square)
console.log(newFn(10));

容器式编程

  • 能够当做容器的类型,类型支撑对容器内元素进行操作
  • 常见的:functor:Array(Iterable).map,Promise.then
a.b != null ? (a.b.c != null ?(a.b.c.d !== a.b.c.d.e :null) : null) :null

….这部分听得实在太费劲了,气泡音听得难受(越过),知道有这个概念,去其他地方学习即可

呼应式编程

维基百科界说:在核算中,呼应式编程反应式编程(英语:Reactive programming)是一种面向数据流和改变传达的声明式编程范式。这意味着能够在编程言语中很方便地表达静态或动态的数据流,而相关的核算模型会主动将改变的值经过数据流进行传达。

  • 通俗来说,呼应式编程便是一种处理数据流的编程办法。咱们能够把数据流当作一条河流,数据就像是水流相同从上游流向下游。在呼应式编程中,咱们能够方便地界说这条河流,并在河流中处理数据的改变,就像是在河流中处理水流相同。这样,咱们就能够很方便地处理数据的改变,而不需求手动追踪和处理每一个数据改变的位置。

没有纯粹的呼应式编程言语,咱们需求借助东西库的帮助,例如RxJS

  • 异步/离散的函数式编程

    • 数据流

    • 操作符

      • 过滤
      • 兼并
      • 转化
      • 高阶

观察者办法

观察者办法(Observer Pattern)是一种规划办法,它界说了一种一对多的依靠联系,让多个观察者目标一同监听某一个主题目标,当主题目标发生改变时,它的一切观察者都会收到告诉并主动更新。

在观察者办法中,有两个中心人物:主题目标和观察者目标。主题目标保护一个观察者列表,并供给增加、删去和告诉观察者的办法;观察者目标则界说了接纳告诉并进行更新的办法。

观察者办法的长处包含:

  1. 松耦合:观察者办法将主题目标和观察者目标之间解耦,使得它们能够独登时改变和扩展。
  2. 可复用性:因为观察者目标能够动态地增加和删去,因而能够在不修正主题目标的状况下增加新的观察者目标,进步了代码的可复用性。
  3. 扩展性:在观察者办法中,能够灵敏地增加和删去观察者目标,因而能够方便地扩展和修正系统的功用。

观察者办法在实践运用中广泛运用,例如GUI界面中的事情处理机制、微信公众号的订阅功用等等。

编程范式(万字笔记) | 青训营笔记

迭代器办法

迭代器办法(Iterator Pattern)是一种规划办法,它供给了一种次序拜访聚合目标中的元素,而不需求露出聚合目标的内部表明。迭代器办法能够将遍历聚合目标的进程从聚合目标中别离出来,从而能够简化聚合目标的完成和遍历算法的完成。

在迭代器办法中,有两个中心人物:聚合目标和迭代器目标。聚合目标是一组目标的调集,它供给了一个办法来获取迭代器目标;迭代器目标则界说了拜访和遍历聚合目标中元素的办法。

迭代器办法的长处包含:

  1. 简化聚合目标的完成:因为迭代器办法将遍历聚合目标的进程从聚合目标中别离出来,因而能够简化聚合目标的完成,使其只需求重视自己的中心业务逻辑。
  2. 进步聚合目标的拜访功率:在迭代器办法中,迭代器目标能够供给不同的遍历算法,从而能够针对不同的运用场景进行优化,进步聚合目标的拜访功率。
  3. 进步代码的可复用性:因为迭代器办法将遍历算法从聚合目标中别离出来,因而能够方便地重用遍历算法,进步代码的可复用性。

迭代器办法在实践运用中广泛运用,例如Java中的Iterator接口、C++中的STL迭代器等等。它能够帮助咱们愈加方便地遍历聚合目标中的元素,进步代码的可读性和可保护性。

  • 能够类比为Promise和EventTraget超集

编程范式(万字笔记) | 青训营笔记

呼应式编程的”compose”

  • 兼并
  • 过滤
  • 转化
  • 反常处理
  • 多播

编程范式(万字笔记) | 青训营笔记

编程范式(万字笔记) | 青训营笔记

总结(思维导图)

编程范式(万字笔记) | 青训营笔记

构建范畴特定言语

范畴特定言语(Domain-Specific Language,简称DSL)是一种专门用于处理特定范畴问题的编程言语。与通用编程言语相比,DSL愈加重视于特定范畴的问题,使得针对该范畴的编程变得愈加高效、简略和直观。

DSL的规划是为了处理特定范畴的问题,因而它能够愈加贴近范畴的需求和特色,供给愈加快捷和高效的处理计划。DSL一般具有简略的语法和丰厚的范畴专业术语,使得开发人员能够愈加专注于处理范畴问题,而无需重视底层技术完成。

DSL的运用场景包含但不限于:配置文件、作业流程、数据剖析、模型界说等。在这些范畴中,DSL能够供给愈加高效、直观和易于保护的处理计划,提高开发功率和代码质量。

  • HTML
  • SQL

与之相对应的是General-purpose language(通用言语)

  • C/C++
  • JavaScript
  • ….

特定言语需求由通用言语完成,通用言语无法由特定言语完成

词法解析

  • 言语运转

编程范式(万字笔记) | 青训营笔记

SQL Token分类

  • 注释
  • 关键字
  • 操作符
  • 空格
  • 字符串
  • 变量

lexer

编程范式(万字笔记) | 青训营笔记

语法剖析

Parser_语法规矩

上下文无关语法规矩

编程范式(万字笔记) | 青训营笔记

  • 推导式:表明非终结符到(非终结符或终结符)的联系。
  • 终结符:构成语句的实践内容。能够简略了解为词法剖析中的token.
  • 非终结符:符号或变量的有限调集。它们表明在语句中不同类型的短语或子句。

Parser_LL

LL:从左到右查看,从左到右构建语法树

编程范式(万字笔记) | 青训营笔记

对应的自顶向下的流程图:

编程范式(万字笔记) | 青训营笔记

Parser_LR

LR:从左到右查看,从右到左构建语法树

LL(K) > LR(1) > LL(1),括号里的内容构建语法树需求向下看的数量

编程范式(万字笔记) | 青训营笔记

东西生成

使用东西让咱们只需求重视语法方面的问题,语法剖析则交给东西来做

编程范式(万字笔记) | 青训营笔记

解说和编译

  • 运转parser.parse后生成如下语法树

编程范式(万字笔记) | 青训营笔记

课程总结

编程范式(万字笔记) | 青训营笔记