Difference between declarative and imperative in React.js?
最近我研究了很多关于Facebook javascript库react.js的功能和使用方法。当谈到它与其他javascript世界的不同之处时,通常会提到两种编程风格:
两者有什么区别?
声明性风格,和react的风格一样,允许您通过说"它应该像这样"来控制应用程序中的流和状态。命令式风格改变了这种情况,允许您通过说"这是您应该做的"来控制应用程序。
声明性的好处在于,您不会陷入表示状态的实现细节中。您正在委派组织组件来保持应用程序视图的一致性,因此您只需担心状态。
想象一下你有一个管家,他是一个框架的隐喻。你想做晚饭。在紧急情况下,你会一步一步地告诉他们如何做晚餐。您必须提供以下说明:
1 2 3 4 5 | Go to the kitchen Open fridge Remove chicken from fridge ... Bring food to the table |
在一个声明性的世界里,你只需要描述你想要什么
1 | I want dinner with chicken. |
如果你的管家不知道如何做鸡肉,那么你就不能以声明式的方式操作。就像主干不知道如何改变自己来完成某项任务一样,你不能只是告诉它去完成这项任务。例如,react可以是声明性的,因为它"知道如何制作鸡肉"。与主干相比,主干只知道如何与厨房连接。
能够描述状态会显著减少bug的表面积,这是一个好处。另一方面,在事情发生的方式上,您可能缺乏灵活性,因为您正在委托或抽象化如何实现状态。
想象一个简单的UI组件,比如"like"按钮。当你轻敲它时,如果它以前是灰色的,它会变成蓝色;如果它以前是蓝色的,它会变成灰色。
这样做的必要方法是:
1 2 3 4 5 6 7 8 9 | if( user.likes() ) { if( hasBlue() ) { removeBlue(); addGrey(); } else { removeGrey(); addBlue(); } } |
基本上,你必须检查屏幕上的当前内容处理用当前状态重新绘制它所需的所有更改,包括撤消以前状态的更改。你可以想象这在现实世界中是多么复杂。
相反,声明性方法是:
1 2 3 4 5 | if( this.state.liked ) { return <blueLike />; } else { return <greyLike />; } |
因为声明性方法分离了关注点,所以它的这一部分只需要处理UI在特定状态下的外观,因此更容易理解。
This is great analogy:
*An imperative response:go out of the North Exit of the Parking Lot and take a left.在你到班杰尔高速公路出口之前像你要去宜家一样离开出口走直了,走直了。继续穿过下一个光线,然后把你的下一个离开。我的房子是
我的地址是298西方不变的Alley,Draper Utah 84020*
HTTPS://Tylermcginnis.com/imperative-vs-declarative-programming/
命令代码:
当Javascript代码被写入命令时,我们就准确地告诉Javascript要做什么和要做什么。想想看,如果我们给了Javascript命令,它应该采取什么步骤。
比如说,我给你一个低调的环路:
1 2 3 4 5 6 | const people = ['Amanda', 'Geoff', 'Michael', 'Richard', 'Ryan', 'Tyler'] const excitedPeople = [] for (let i = 0; i < people.length; i++) { excitedPeople[i] = people[i] + '!' } |
这是命令代码,尽管。我们指挥Javascript每一步都要做些什么We're commanding Javascript what to do at every single step.我们必须下令:
宣言守则:
以宣言代码,我们并不是一步步一步地把我们带到最后。相反,我们宣布了我们想要做的事,而我将把事情做好。这是一个比特摘要,让我们看一个例子。Let's take the imperative for loop code we were just looking at and reflector it to be more declarative.
有了强制性的密码,我们就形成了所有的步骤,最终取得了结果。我们到底想要什么呢?Well,our starting point was just an array of names:
ZZU1
我们想要的最终目标是同一个名字的阵列,但每一个名字的末尾都有一个感叹符号:
1 | ["Amanda!","Geoff!","Michael!","Richard!","Ryan!","Tyler!"] |
从开始到结束,我们将使用Javascript的地图()功能来说明我们想要做的事情。
1 | const excitedPeople = people.map(name => name + '!') |
就是这样!Notice that with this code we have not:
创建一个项目对象当它停止运行时告诉代码使用Iterator访问人群阵列中的特定项目在激励人群阵列中保存每一个新条纹…所有这些步骤都是通过Javascript的地图()阵列方法进行的。
最好将react(声明性)和jquery(命令性)进行比较,以显示不同之处。
在react中,您只需要在render()方法中描述UI的最终状态,而不必担心如何从以前的UI状态转换到新的UI状态。例如。,
1 2 3 4 5 | render() { ... <Label value={this.state.lastPrice} ... /> <Label value={this.state.askPrice} ... /> } |
另一方面,jquery要求您强制转换UI状态,例如,选择label元素并更新其文本。
1 2 3 4 5 | update() { ... $("#last-price-label").val(lastPrice); $("#ask-price-label").val(askPrice); } |
在现实场景中,将有更多的UI元素需要更新,加上它们的属性(例如,CSS样式和事件侦听器)等。如果您强制使用jquery,它将变得复杂和乏味;很容易忘记更新UI的某些部分,或者忘记删除旧的偶数侦听器(内存泄漏)等。这是出现错误,即UI状态和模型状态不同步。
状态不同步永远不会发生在React的声明性方法中,因为我们只需要更新模型状态,React负责保持UI和模型状态同步。
- 在钩子下,react将使用命令式代码更新所有更改的DOM元素。
您也可以阅读我的答案,说明性编程和命令式编程有什么区别?.
ps:从上面的jquery示例中,您可能会想,如果我们将所有的DOM操作都放在update()方法中,并且每当模型状态发生变化时都调用它,那么我的UI就永远不会失去同步。您是正确的,这实际上就是react render()所做的,唯一的区别是jquery update()将导致许多不必要的DOM操作,但react将仅使用其虚拟DOM diffing算法更新更改的DOM元素。
我将从一个类比开始:我有两辆车,在我的两辆车里,我希望车内的温度是正常的室温~72°F。在第一辆(老款)车里,有两个旋钮控制温度(一个旋钮控制温度,一个旋钮控制气流)。当天气太热的时候,我必须调整第一个旋钮来降低温度,可能会改变气流),如果天气太冷的话,我还得调整另一个旋钮。这是当务之急!我得自己管理旋钮。在我的第二辆(更新的)车里,我可以设定/申报温度。这就意味着我不必摆弄旋钮来调节我的车知道我申报/设定的温度为72°F,我的车将做必要的工作来达到那个状态。
react是相同的,您声明标记/模板和stat,然后react执行必要的工作,以使dom与您的应用程序保持同步。
我们不使用
命令式代码指示JavaScript如何执行每个步骤。通过声明性代码,我们告诉javascript我们想要做什么,让javascript负责执行这些步骤。
react是声明性的,因为我们编写我们想要的代码,react负责获取我们声明的代码,并执行所有的javascript/dom步骤,以获得我们想要的结果。
- 声明性允许您控制所有视图。(就像国家管理一样)
- 命令允许您控制视图。(就像美元(这个)