命令式编程和声明式编程的思想
前言
事情是这样的,某天我正在了解React的特性,里面有一句是React采用了声明式的编程风格,于是我就顺着声明式编程这几个字眼去继续了解了相关知识,本篇文章主要讲述非声明式编程和声明式编程的不同,以及流程图和状态机的相关知识。
基本概念
命令式编程(非声明式编程):它是一种面向过程的编程范式,它将计算过程看作是一系列命令的执行。在命令式编程中,程序员需要定义每个步骤的操作,并指定这些操作的执行顺序。例如,可以使用流程图来表示命令式编程中的步骤和操作。示例代码:
function findMax(arr) {
let max = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
const arr = [1, 5, 3, 8, 2];
const max = findMax(arr);
console.log(max); // 8
声明式编程:它是一种面向对象的编程范式,它将计算过程看做一系列状态的改变,将计算的结果看做是这些状态的值。在声明式编程中,程序员需要定义每一个状态和对应的操作,然后根据这些操作来执行计算。例如,可以使用状态机来表示声明式编程的状态和操作。示例代码:
const arr = [1, 5, 3, 8, 2];
const max = arr.reduce((prev, cur) => prev > cur ? prev : cur);
console.log(max); // 8
流程图和状态机
上文中提到了流程图和状态机,我想大部分人对于流程图还是比较了解和清楚的,那状态机又是什么呢?来顺便了解一下吧
基本概念
首先,流程图是一种以有向图形式表示计算过程的工具。在流程图中,每个节点代表一个操作或状态,而每条边则代表一个转换,即从一个操作或状态转换到另一个操作或状态。流程图通常用于描述一个计算机程序的执行流程,例如在编程语言中描述顺序、分支、循环等等。
状态机则是一种以有向图形式表示计算过程中各种可能的状态的工具。在状态机中,每个状态代表一个特定的输入或状态,而每个转换则是指从一个状态转换到另一个状态的过程。状态机通常用于描述一个计算机系统中各种可能的状态和操作,例如操作系统中的进程、网络协议中的状态、软件应用中的状态等等。
乍一看,是不是感觉有很多相似之处,确实两者之间有很多相似之处,但它们在表示计算过程中的方式、可视化程度、以及表达复杂计算过程的能力方面有所不同。因此,在不同的场景下,可以选择使用不同的工具来表示计算过程。
常见形状
流程图
- 开始/结束方框:一个圆形或椭圆形,表示程序或过程的开始或结束点。
- 处理方框:一个矩形,表示程序或过程的处理步骤。通常会在方框内部写下具体的指令或操作。
- 条件方框:一个菱形,表示程序或过程需要根据不同的条件进行分支。通常在菱形内写下条件语句,例如 if 语句。
- 输入/输出方框:一个平行四边形,表示程序或过程需要读取或输出数据。通常在方框内部注明要读取或输出的数据类型。
- 连接线:表示程序或过程中各个步骤之间的顺序和逻辑关系。箭头的方向表示数据的流动方向。
- 注释:表示对图示的解释、说明、补充信息等,放在方框外面沿着连接线走向。
- 子程序:由双竖杠符号“||”标记,用于重复利用已有的程序。
除了上述这些基本符号外,还有一些其他的常见符号,例如循环方框,预定义过程方框,项目标识符和库函数等。总之,流程图的符号主要用于表示程序或业务过程中的不同步骤、分支和数据流动。
状态机
- 状态:通常用圆圈或圆角矩形表示,它表示系统所处的固定条件或情况,状态机的所有处理逻辑都构建在状态之上。
- 转移:通过箭头标识当前状态向下一个状态的转换关系,其中箭头通常伴随着由触发该转换的事件或输入信号所标识。
- 起始状态:起始状态是状态机的起点,通常以特殊的法线箭头标识。当收到第一个输入信号时,状态机会从此状态开始执行相应的动作。
- 终止状态:在状态机中,终止状态指定了一个结束状态或中断状态,它通常代表状态机的目标,以双环来表示。
- 动作:通常用矩形框表示,它描述了某个事件触发了状态的转移所带来的重复性行为。
- 意外退出:这个状态意味着系统严重故障,需要进行清理操作并重新初始化系统。
除了上述这些基本符号外,还有一些其他的常见符号,如默认转移、同步状态机等。总之,状态机符号主要用于表示状态及状态之间的转移以及转移所对应事件和动作。
具体例子
流程图
状态机
注:流程图和状态机可以结合使用,通过流程图描述程序的整体流程和结构,通过状态机描述程序的局部状态和转换过程。
例子
接下里用两段代码来说明命令式编程和声明式编程的不同-----往列表里添加节点
命令式编程
<body>
<div>
<button id="btn">添加消息</button>
<ul id="list">
<li>消息1</li>
<li>消息2</li>
</ul>
</div>
<script>
let btn = document.querySelector('#btn')
let list = document.querySelector('#list')
btn.onclick = function () {
let newMessage = '消息' + (list.childElementCount + 1)
let newLi = document.createElement('li')
newLi.innerHTML = newMessage
list.appendChild(newLi)
}
</script>
</body>
声明式式编程
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function Message() {
let [message, setMessage] = React.useState([{
id: 1,
message: "消息"
}, {
id: 2,
message: "消息"
}])
return (<div>
<button onClick={() => {
message.push({
id: message.length + 1,
message: '消息'
});
setMessage([...message])
}}
>添加信息</button>
<ul>
{
message.map((item) => {
return (<li key={item.id}>{item.message}{item.id}</li>)
})
}
</ul>
</div>)
}
const domContainer = document.querySelector('#root');
const root = ReactDOM.createRoot(domContainer);
root.render(<Message />);
</script>
</body>
</html>
从这两个例子可以很明显的看出,命令式编程我们需要手动去创建dom,去添加dom,一步一步的告诉电脑应该怎么执行;而在声明式编程中,我们只需要关注状态的改变。
结语
命令式和声明式编程都可以用来解决问题,但它们的思维方式不同。命令式编程偏重于明确地控制程序流程,而声明式编程则更注重描述我们需要的结果。
React 采用声明式编程模型,使得编写以数据为中心的应用程序更加容易,而无需手动管理 DOM、事件处理等行为。
转载自:https://juejin.cn/post/7238869983622316088