React.js 中陈述式和祈使式的区别?

最近我一直在研究 Facebook JavaScript 库 React.js 的功能和使用方法。当谈到它与其他 JavaScript 世界的差异时,通常会提到两种编程风格 declarativeimperative

两者有什么区别?

71942 次浏览

声明式样式,比如 response 的样式,允许您通过声明“ It should look like this”来控制应用程序中的流和状态。命令式风格扭转了这种局面,允许您通过说“这是您应该做的”来控制应用程序。

声明式的好处是您不会陷入表示状态的实现细节中。您正在委托组织组件来保持应用程序视图的一致性,因此您只需要担心状态。

假设你有一个管家,他是一个框架的隐喻。你想做晚饭。在一个命令式的世界里,你会一步一步地告诉他们如何做晚餐。你必须提供以下指示:

Go to the kitchen
Open fridge
Remove chicken from fridge
...
Bring food to the table

在一个陈述性的世界里,你可以简单地描述你想要的东西

I want dinner with chicken.

如果你的管家不知道如何做鸡肉,那么你就不能以陈述式的方式操作。就像如果 Backbone 不知道如何变异它自己来完成某个任务一样,你不能只是告诉它去做那个任务。例如,React 之所以能够是陈述性的,是因为它“知道如何制作鸡肉”。相比之下,Backbone 只知道如何与厨房接口。

能够描述状态大大减少了 bug 的表面积,这是一个好处。另一方面,您可能在 怎么做中缺乏灵活性,因为您委派或抽象了如何实现状态。

想象一个简单的 UI 组件,比如“ Like”按钮。当你点击它的时候,如果之前是灰色,它会变成蓝色,如果之前是蓝色,它会变成灰色。

这样做的必要方式是:

if( user.likes() ) {
if( hasBlue() ) {
removeBlue();
addGrey();
} else {
removeGrey();
addBlue();
}
}

基本上,你必须检查什么是当前在屏幕上和 处理用当前状态重新绘制它所需的所有更改,包括撤消对以前状态的更改。你可以想象这在现实世界中会有多复杂。

相比之下,声明式的做法将是:

return this.state.liked ? <blueLike /> : <greyLike />;

因为声明性方法分离关注点,所以它的这一部分只需要处理 UI 在特定状态下的外观,因此更容易理解。

这是一个很好的类比:

* 必要的回应 : 从停车场的北出口出去,然后左转。上15号州际公路往南直到 Bangerter Highway 出口。出口右转,就像去宜家一样。一直走,在第一个红绿灯处右转。继续通过下一个红绿灯,然后在下一个路口左转。我的房子是298英镑。

我的地址是犹他州 Draper 84020 West Immutable Alley 298号 *

Https://tylermcginnis.com/imperative-vs-declarative-programming/

最好比较 React (声明式)和 JQuery (命令式)以显示差异。

在 React 中,您只需要在 render()方法中描述 UI 的最终状态,而不必担心如何从以前的 UI 状态转换到新的 UI 状态。例如:

render() {
const { price, volume } = this.state;
const totalPrice = price * volume;


return (
<div>
<Label value={price} className={price > 100 ? 'expensive' : 'cheap'} ... />
<Label value={volume} className={volume > 1000 ? 'high' : 'low'} ... />
<Label value={totalPrice} ... />
...
</div>
)
}

另一方面,JQuery 要求您必须转换 UI 状态,例如,选择 label 元素并更新它们的文本和 CSS:

updatePrice(price) {
$("#price-label").val(price);
$("#price-label").toggleClass('expansive', price > 100);
$("#price-label").toggleClass('cheap', price < 100);


// also remember to update UI depending on price
updateTotalPrice();
...
}


updateVolume(volume) {
$("#volume-label").val(volume);
$("#volume-label").toggleClass('high', volume > 1000);
$("#volume-label").toggleClass('low', volume < 1000);
  

// also remember to update UI depending on volume
updateTotalPrice();
...
}


updateTotalPrice() {
const totalPrice = price * volume;
$("#total-price-label").val(totalPrice);
...
}

在真实的场景中,将会有更多的 UI 元素需要更新,以及它们的属性(例如 CSS 样式和事件侦听器)等等。如果您使用 JQuery 来完成这项任务,那么它将变得复杂和乏味; 很容易忘记更新 UI 的某些部分,或者忘记删除旧的事件处理程序(导致内存泄漏或 处理者多次开枪) ,等等。这就是 bug 发生的地方,也就是说,UI 状态和模型状态不同步。

React 的声明式方法永远不会出现状态不同步的情况,因为我们只需要更新模型状态,而 React 负责保持 UI 和模型状态同步。

  • 在钩子下,React 将使用命令式代码更新所有已更改的 DOM 元素。

你也可以阅读我对 在编程中,声明式范例和命令式范例的区别是什么?的回答。

PS: 从上面的 jQuery 例子中,您可能会想,如果我们将所有的 DOM 操作放在一个 updateAll()方法中,并在每次我们的模型状态发生变化时调用它,那么 UI 将永远不会失去同步。您是正确的,这正是 React 所做的,唯一的区别是 jQuery updateAll()会导致许多不必要的 DOM 操作,但 React 只会使用它的 虚拟正射影像差分算法更新已更改的 DOM 元素。

命令式代码指导 JavaScript 如何执行每个步骤。通过声明性代码,我们告诉 JavaScript 我们想要做什么,并让 JavaScript 负责执行这些步骤。

React 是声明性的,因为我们编写我们想要的代码,而 React 负责获取我们声明的代码,并执行所有 JavaScript/DOM 步骤,以获得我们想要的结果。

我先打个比方: 我有两辆车,在我的两辆车里,我希望车内的温度是常温 ~ 72 ° F。在第一辆(较旧的)车上,有两个旋钮控制温度(1个旋钮控制温度,1个旋钮控制气流)。当它变得太热,我必须调整第一个旋钮,以降低温度,也许改变气流) ,反之亦然,如果它太冷。这是紧急任务!我必须自己控制旋钮。在我的第二辆(较新的)车里,我可以设定/宣布温度。这意味着我不需要摆弄旋钮来调节温度我的车知道我声明/设置它为72华氏度,我的车将做必要的工作来达到这个状态。

React 也是一样,你声明标记/模板,然后 stat 执行必要的工作来保持 DOM 与应用程序同步。

<button onClick={activateTeleporter}>Activate Teleporter</button>

我们不使用 .addEventListener()来设置事件处理,而是声明我们想要的。当单击按钮时,它将运行 activateTeleporter函数。

在命令式世界中,一个现实生活中的例子是进入一个酒吧喝啤酒,然后给酒保下面的指示:

——从架子上拿一个杯子

——把玻璃放在通风口前面

——拉下把手,直到杯子满了

把杯子递给我。

相反,在陈述性的世界里,你只需要说: “啤酒,谢谢。”.在声明式风格中,我们编写代码的方式,而不是如何编写。

在宣告式编程中,开发人员只描述他们想要实现的目标,不需要列出所有的步骤。这使您的代码更加简单,并且具有可读性。但是,在命令式样式中,开发人员逐步定义任务。

例如 For-loop 是命令式样式,因为您声明了起始点、结束点和间隔。但是,Array.map是一个声明性表达式。

React 提供了一种声明性方法,这使得它很容易使用,因此,生成的代码很简单,这通常会导致更少的错误和更多的可维护性。

因为 React 遵循一个声明性的范例,并且没有必要告诉它如何与 DOM 交互; 您只需声明您想在屏幕上看到的内容,React 就可以完成这项工作。

宣告式编程是一个编程范型... 它表达了一个计算的逻辑而不是描述它的控制流。

命令式编程是一个编程范型,它使用改变程序状态的语句。

参考链接:-https://codeburst.io/declarative-vs-imperative-programming-a8a7c93d9ad2

陈述式与命令式

宣告式编程就像让你的朋友粉刷你的房子。你根本不在乎他们怎么清理,用什么颜色来涂,用了多少资源来完成。

//Declarative For Searching element from an array
array.find(item)

声明式的反义词是祈使式 你告诉你的朋友该怎么粉刷你的房子。

  • 用洗涤剂洗房子。
  • 用纳罗拉克颜料或亚洲颜料
  • 把屋顶漆成绿色。
  • 让3个会员签约等等。

命令式算法

def imperative_search(array, item)
for i in array do
if i == item
return item
end
end
return false
end

到目前为止,我的理解是:

声明性代码(几乎?)总是代码之上的一个抽象层,在本质上更加命令式。

React 允许您编写声明性代码,这些代码是直接与 DOM 交互的命令式代码之上的一个抽象层(例如。差分算法).如果您需要编写命令式代码(即。直接与 DOM 交互) React 提供 作为逃生舱口

宣告式编程是一种编程风格,其中应用程序的结构按照优先顺序排列 描述应该发生什么,而不是定义应该如何发生。

为了理解宣告式编程,让我们比较一下命令式编程的编程风格 关注如何使用代码实现结果)。

示例: 使字符串 URL 友好。通常,这可以通过用连字符替换字符串中的所有空格来实现, 因为空格不是 URL 友好的。首先,这项任务的必要方法:

const string = "difference between declarative and imperative in react.js";
const urlFriendly = "";
for (var i = 0; i < string.length; i++) {
if (string[i] === " ") {
urlFriendly += "-";
} else {
urlFriendly += string[i];
}
}
console.log(urlFriendly); // "difference-between-declarative-and-imperative-in-react-js"

在本例中,我们循环遍历字符串中的每个字符,在出现空格时替换它们。这个计划的结构只关心如何完成这样一个任务。我们使用 for 循环和 if 语句,并使用相等运算符设置值。只是 仅仅查看代码并不能告诉我们太多,因为命令式程序需要大量注释才能理解发生了什么。

现在让我们来看一个解决同一问题的声明性方法:

const string = "Difference between declarative and imperative in React.js?";
const urlFriendly = string.replace(/ /g, "-");
console.log(urlFriendly);

这里我们使用 string.replace和正则表达式来 用连字符替换所有空格实例 一种描述应该发生什么的方法: 字符串中的空格 如何处理空间的细节如下 抽象出来的替换函数。

在声明性程序中,语法本身描述应该发生的事情,而事情如何发生的细节被抽象出来。

从本质上讲,宣告式编程产生的应用程序更容易推理,当推理一个应用程序更容易时,这个应用程序就更容易扩展。有关宣告式编程模式的其他详情,请参阅 宣告式编程维基

现在,让我们考虑构建文档对象模型的任务。必须采取的做法涉及如何构建 DOM:

const target = document.getElementById("target");
const wrapper = document.createElement("div");
const headline = document.createElement("h1");
wrapper.id = "welcome";
headline.innerText = "Hello World";
wrapper.appendChild(headline);
target.appendChild(wrapper);

此代码涉及到创建元素、设置元素和 将它们添加到文档中。很难进行更改, 添加特性,或者在 DOM 所在的位置增加10,000行代码 建造的命令。

现在让我们看看如何声明性地构造 DOM 使用 React 组件:

const { render } = ReactDOM;
const Welcome = () => (
<div id="welcome">
<h1>Hello World</h1>
</div>
);


render(<Welcome />, document.getElementById("target"));

React 是声明性的 渲染函数使用指令 在组件中声明以构建 DOM,将 如何呈现 DOM 的细节。我们可以清楚地看到,我们 希望将我们的 Welcome 组件呈现到 ID 为 目标

资料来源: 开发应用程序的现代模式

解释每一个步骤是一种命令式的方法。我们必须创建一个段落标签与 Hello World!在里面发短信。

//Imperative


const para = document.createElement('p');
para.innerText = 'Hello World !';
document.querySelector('#root').appendChild(para);

定义所需的最终目标状态,而不指定确切的过程。例如,使用文本的 p 标记,而不告诉 createElement 或 innerText

 //Declarative


import React from "react";
import ReactDOM from "react-dom";
 

const App = () =>{
return(<p>Hello World !</p>);
}


ReactDOM.render(<App />, document.getElementById("root"));