声明式更适合程序员的编程思路,而命令式却是我们实际开发中一直在写的,要学会在实际中多用声明式编程。

 

声明式和命令式编程

At this point you’ve undoubtedly heard about imperative programming vs declarative programming. You might have even searched for what those terms actually mean.

至此,您无疑已经听说了命令式编程与声明式编程。 您甚至可能已经搜索了这些术语的实际含义。

Sadly, you probably encountered a definition similar to this, “You know, imperative programming is like “how” you do something, and declarative programming is more like “what” you do, or something.”

可悲的是,您可能会遇到类似于以下的定义:“您知道,命令式编程就像“您如何做某事,而声明式编程更像您在做什么”。

That definition makes perfect sense once you actually know the difference between imperative and declarative — but you don’t, which is why you asked the question in the first place. It’s like trying to answer “What came first, the chicken or the egg?” except everyone seems to think the chicken did, but you don’t even like eggs, and you’re confused.

一旦您真正了解了命令性和声明性之间的区别,该定义就很有意义了,但是您却没有,这就是为什么您首先提出问题的原因。 就像试图回答“先来的是鸡还是鸡蛋?” 除了每个人似乎都认为鸡肉确实如此,但您甚至不喜欢鸡蛋,而且感到困惑。

Combine this frustration with the bastardization of the actual word “declarative” to basically just mean “​​good​​” and all of a sudden your imposter syndrome is tap dancing on your confidence, and you realize you don’t even like programming that much.

将此挫败感与实际的“说明性”一词的混蛋结合起来,基本上就意味着“ ​​好​​ ”,突然间,冒名顶替者综合征就是在自信的鼓舞下,您意识到自己甚至不喜欢编程。

Don’t worry though, friend. I don’t know what a monad is, so hopefully this post will help you realize that declarative is more than just being “easy to reason about” and “good.”

朋友,请不要担心。 我不知道什么是monad,所以希望这篇文章可以帮助您认识到声明式不仅仅是“容易推理”和“好”。

The hard part about this topic is, as ​​Merrick​​ has observed, “It’s one of those things you have an intuition about but can’t seem to explain.”

正如​​Merrick​​所观察到的,有关此主题的困难部分是:“这是您有直觉但似乎无法解释的事情之一。”

I’ve talked with many developers and what seems to help most is a combination of metaphors with actual code examples. So buckle up cause I’m about to #preach.

我已经与许多开发人员进行了交谈,似乎最有帮助的是隐喻与实际代码示例的结合。 所以请系好安全带,因为我要#preach。

Let’s go back to the initial definition I made fun of, “Imperative programming is like “How” you do something and declarative programming is more like “What” you do.” There’s actually SOME good information hidden in here. Let’s first see the merit in this definition by taking it out of the context of programming and look at a “real life” example.

让我们回到我取笑的最初定义:“命令式编程就像您如何做,而声明式编程更像您在做什么”。 实际上,这里隐藏了一些很好的信息。 首先,让我们从编程的上下文中了解该定义的优点,并看一个“现实生活”示例。

You decide that you’ve been spending too much time arguing about “JavaScript Fatigue”™ and Reactive Functional Programming, and your husband deserves a nice date. You decide to go to Red Lobster since you’ve been listening to a lot of Beyonce lately. ??. You arrive at Red Lobster, approach the front desk and say…

您决定花太多时间争论“ JavaScript Fatigue”™和响应式功能编程,而丈夫应该得到一个愉快的约会。 您决定去红龙虾,因为您最近一直在听很多碧昂丝的音乐。 ??。 您到达红龙虾,靠近前台说……

An imperative approach (HOW): I see that table located under the Gone Fishin’ sign is empty. My husband and I are going to walk over there and sit down.

一种命令式方法(HOW):我看到位于Gone Fishin'标志下的桌子是空的。 我和我丈夫要去那边坐下。

A declarative approach (WHAT): Table for two, please.

声明性方法(WHAT):请为两个表。

The imperative approach is concerned with HOW you’re actually going to get a seat. You need to list out the steps to be able to show HOW you’re going to get a table. The declarative approach is more concerned with WHAT you want, a table for two.

命令式方法与您实际将如何获得座位有关。 您需要列出步骤以显示如何获取表格。 声明式方法与您想要的东西有关,一个两个人的表。

“Ok.” — your brain

“好。” - 你的脑

More metaphors!

更多的隐喻!

I’m going to ask you a question. I want you to think of both an imperative response and a declarative response.

我要问你一个问题。 我希望您同时考虑命令式响应和声明式响应。

“I’m by Wal-Mart. How do I get to your house from here?”

“我在沃尔玛。 我怎么从这里到你家?”

An imperative response: Go out of the north exit of the parking lot and take a left. Get on I-15 south until you get to the Bangerter Highway exit. Take a right off the exit like you’re going to Ikea. Go straight and take a right at the first light. Continue through the next light then take your next left. My house is #298.

当务之急是:从停车场北出口出来,向左走。 在I-15州际公路上向南行驶,直到到达Bangerter Highway出口。 就像您要去宜家一样,在出口处右转。 一直走,在第一个路口右转。 继续穿过下一盏灯,然后左下。 我的房子是#298。

A declarative response: My address is 298 West Immutable Alley, Draper Utah 84020

声明式答复:我的地址是犹他州德拉珀84020西不可变巷298号

Regardless of how I get to your house, what really matters is the car I drive. Am I going to drive an imperative stick shift car or a declarative automatic car. Enough metaphors?

不管我怎么到你家,真正重要的是我开车。 我要驾驶命令式变速杆汽车还是声明式自动挡汽车。 足够的隐喻?

Before we dive into code, it’s important to realize that many declarative approaches have some sort of imperative abstraction layer. Look at all of our examples:

在深入研究代码之前,必须意识到许多声明性方法具有某种命令性抽象层。 看我们所有的例子:

The declarative response to the Red Lobster employee is assuming that the Red Lobster employee knows all the imperative steps to get us to the table. Knowing the address assumes you have some sort of GPS that knows the imperative steps of how to get to your house.

对Red Lobster员工的声明性响应是假设Red Lobster员工了解使我们上桌的所有必要步骤。 知道地址就意味着您拥有某种GPS,该GPS知道如何到达房屋的必要步骤。

An automatic car has some sort of abstraction layer over shifting gears.

自动驾驶汽车在变速杆上有某种抽象层。

That was the realization that really made it click for me, so I’ll repeat it: Many (if not all) declarative approaches have some sort of underlying imperative abstraction.

那就是真正让我为之点击的认识,所以我重复一遍:许多(如果不是全部的话)声明性方法都具有某种底层的命令式抽象。

If that sentence makes sense, you’re doing great!

如果这句话有意义,那么您做得很好!

Now, we’re going to attempt to take the leap from metaphorical happy land to real world code land. To make the leap more graceful, let’s look at some programming “languages” that are inherently declarative versus those which are imperative by nature.

现在,我们将尝试从隐喻的幸福之地迈向现实世界的代码之地。 为了使过渡更加顺畅,让我们看一下本质上是声明性的程序设计“语言”与本质上是命令性的编程“语言”。

Imperative: C, C++, JavaDeclarative: SQL, HTML(Can Be) Mix: JavaScript, C#, Python

命令式:C,C ++,Java声明式:SQL,HTML(Can Be)组合:JavaScript,C#,Python

Think about your typical SQL or HTML example,

考虑一下您的典型SQL或HTML示例,

SELECT * FROM Users WHERE Country=’Mexico’;
<article>  <header>    <h1>Declarative Programming</h1>    <p>Sprinkle Declarative in your verbiage to sound smart</p>  </header></article>


By glancing at both examples, you have a very clear understanding of what is going on. They’re both declarative. They’re concerned with WHAT you want done, rather than HOW you want it done.

通过看两个例子,您对正在发生的事情有了非常清楚的了解。 它们都是声明性的。 他们关心的是您要完成的工作,而不是要如何完成。

You’re describing what you’re trying to achieve, without instructing how to do it. The implementation of selecting all of the users who live in Mexico has been abstracted from you. You’re not concerned with how the web browser is parsing your article and displaying it to the screen. Your WHAT is Mexican users and a new header and paragraph on your website.

您正在描述要实现的目标,而没有指示如何实现。 选择您居住在墨西哥的所有用户的实施方法已经抽象。 您不必担心Web浏览器如何解析您的文章并将其显示在屏幕上。 您是墨西哥用户 ,您的网站上有一个新的标题段落 。

So far so good. Let’s dive into more practical JavaScript examples.

到目前为止,一切都很好。 让我们深入研究更实用JavaScript示例。

I want you to pretend you’re now in a technical interview and I’m the interviewer. Open up your console and answer the following questions.

我要你假装你现在正在接受技术面试,我是面试官。 打开控制台并回答以下问题。

  1. Write a function called double which takes in an array of numbers and returns a new array after doubling every item in that array. double([1,2,3]) -> [2,4,6]
    编写一个称为double的函数,该函数接受一个数字数组,并在将该数组中的每个项目加倍后返回一个新数组。 double([1,2,3])-> [ 2,4,6]
  2. Write a function called add which takes in an array and returns the result of adding up every item in the array. add([1,2,3]) ->; 6
    编写一个名为add的函数,该函数接收一个数组并返回将数组中每个项目相加的结果。 add([1,2,3])-> ; 6
  3. Using jQuery (or vanilla JavaScript), add a click event handler to the element which has an id of “btn”. When clicked, toggle (add or remove) the “highlight” class as well as change the text to “Add Highlight” or “Remove Highlight” depending on the current state of the element.
    使用jQuery(或普通JavaScript),将点击事件处理程序添加到ID为“ btn”的元素 单击时,切换(添加或删除) “突出显示”类,并根据元素的当前状态将文本更改为“添加突出显示”“删除突出显示” 。

Let’s look at the most common approaches to these problems, which all happen to also be imperative approaches.

让我们看一下解决这些问题的最常用方法,所有这些方法碰巧也是必不可少的方法。

function double (arr) {  let results = []  for (let i = 0; i < arr.length; i++){    results.push(arr[i] * 2)  }  return results}


2.

2。

function add (arr) {  let result = 0  for (let i = 0; i < arr.length; i++){    result += arr[i]  }  return result}


3.

3。

$("#btn").click(function() {  $(this).toggleClass("highlight")  $(this).text() === 'Add Highlight'    ? $(this).text('Remove Highlight')    : $(this).text('Add Highlight')})


By examining what all three of these imperative examples have in common, we’ll be able to better identify what actually makes them imperative.

通过研究这三个必要命令示例的共同点,我们将能够更好地确定实际上使它们成为必需命令的原因。

  1. The most obvious commonality is that they’re describing HOW to do something. In each example we’re either explicitly iterating over an array or explicitly laying out steps for how to implement the functionality we want.
    最明显的共性是他们在描述如何做某事。 在每个示例中,我们要么明确地遍历数组,要么明确提出有关如何实现所需功能的步骤。
  2. This one might not be as obvious if you’re not used to thinking in the “declarative” or even more specifically “functional” way. In each example we’re mutating some piece of state (If you’re unfamiliar with the term state, it’s basically information about something held in memory— which should sound a lot like variables.) In the first two examples we create a variable called results and then we continually modify it. In the third example we don’t have any variables, but we still have state living in the DOM itself — we then modify that state in the DOM.
    如果您不习惯于以“ 声明式 ”或更具体地以“ 功能性 ”方式思考,这一点可能并不那么明显。 在每个示例中,我们都在改变状态的一部分(如果您不熟悉状态一词,它基本上是有关内存中所保存内容的信息,这听起来很像变量。)在前两个示例中,我们创建了一个变量,称为结果,然后我们不断对其进行修改。 在第三个示例中,我们没有任何变量,但是状态仍然存在于DOM本身中-然后在DOM中修改该状态。
  3. This one is a bit subjective, but to me the code above isn’t very readable. I can’t just glance at the code and understand what’s going on. My brain needs to step through the code just as an interpreter would while also taking into account the context in which the code lives (another negativity of mutable data). 
    这有点主观,但是对我来说上面的代码不是很可读。 我不能只是看一眼代码并了解发生了什么。 我的大脑需要像解释器一样逐步执行代码,同时还要考虑代码所处的上下文(可变数据的另一种否定性)。

All right, enough ?ing on the code. Let’s now take a look at some declarative examples. The goal is to fix all the problems from above. So each example needs to describe WHAT is happening, can’t mutate state, and should be readable at a glance.

好吧,代码上的代码足够了。 现在让我们看一些声明性示例。 目标是从上面解决所有问题。 因此,每个示例都需要描述正在发生的事情,不能改变状态,并且一目了然。

1.

1。

function double (arr) {  return arr.map((item) => item * 2)}


2.

2。

function add (arr) {  return arr.reduce((prev, current) => prev + current, 0)}


3.

3。

<Btn   onToggleHighlight={this.handleToggleHighlight}  highlight={this.state.highlight}>     {this.state.buttonText}</Btn>


Much better ?

好多了 ?

Notice that in the first two example we’re leveraging JavaScript’s built in map and reduce methods. This goes back to what we’ve been talking about over and over in this article that most declarative solutions are an abstraction over some imperative implementation.

注意,在前两个示例中,我们利用了JavaScript的内置mapreduce方法。 这可以回溯到我们在本文中反复讨论的内容,即大多数声明性解决方案都是对某些命令性实现的抽象。

In every example we’re describing WHAT we want to happen rather than HOW (we don’t know HOW map and reduce are implemented, we also don’t care). We’re not mutating any state. All of the mutations are abstracted inside of map and reduce. It’s also more readable (once you get used to map and reduce, of course).

在每个示例中,我们都在描述我们要发生的事情,而不是HOW(我们不知道HOW map和reduce的实现方式,我们也不在乎)。 我们不会改变任何状态。 所有的变异都在map内部进行了抽象并精简 。 它也更具可读性(当然,一旦您习惯了映射reduce )。

Now what about #3? Well I cheated a little bit, and am using ​​React​​ — but note that all three imperative mistakes are still fixed. The real beauty of React is that you can create these declarative user interfaces. By looking at our Btn component, I’m able to easily understand what the UI is going to look like. Another benefit is instead of state living in the DOM, it lives in the React component itself.

现在#3呢? 好吧,我作弊了一点,并且正在使用​​React​​ –但是请注意,这三个命令性错误仍然是固定的。 React的真正魅力在于您可以创建这些声明性用户界面。 通过查看我们的Btn组件,我可以轻松了解UI的外观。 另一个好处是它不存在于DOM中,而是存在于React组件本身中。

Another less-spoken-of benefit to declarative code is that your program can be context-independent. This means that because your code is concerned with what the ultimate goal is — rather than the steps it takes to accomplish that goal — the same code can be used in different programs, and work just fine.

声明性代码的另一点好处是您的程序可以独立于上下文。 这意味着,因为您的代码关注的是最终目标是什么,而不是实现目标所需要的步骤,所以同一代码可以在不同的程序中使用,并且工作正常。

Look at all three of our examples above. We can consume both functions and component in any program we want. They’re program agnostic. This is hard to do with imperative code because often times, by definition, imperative code relies on the context of the current state.

查看上面的所有三个示例。 我们可以在任何想要的程序中使用函数和组件。 它们与程序无关。 用命令式代码很难做到这一点,因为根据定义,命令式代码通常依赖于当前状态的上下文。

One thing that I didn’t go too far into is how functional programming is a subset of declarative programming. If you haven’t already, I highly recommend getting more familiar with functional programming techniques in JavaScript. Start with .map, .reduce, .filter and work your way up from there.

我没有深入探讨的一件事是函数式编程是声明式编程的子集。 如果您还没有的话,我强烈建议您熟悉JavaScript中的函数式编程技术。 从.map,.reduce,.filter开始,然后从那里开始。

Odds are there isn’t a lower hanging fruit to improve your codebase than making it more functional.

奇怪的是,除了使代码库更具功能性之外,没有什么比它更加有用的了。

With all of this said, one of my favorite things is to find definitions on the internet where the creator of said definition was more concerned with sounding intelligent than providing a useful, consumable definition. Imperative vs declarative has SO many good examples of this. Enjoy!

综上所述,我最喜欢的事情之一是在互联网上查找定义,其中,该定义的创建者更关心听起来智能,而不是提供有用的,可消耗的定义。 命令式与声明式有很多很好的例子。 请享用!

Declarative programming is “the act of programming in languages that conform to the mental model of the developer rather than the operational model of the machine”.声明式编程是“用符合开发人员心理模型而不是机器操作模型的语言进行编程的行为”。Declarative Programming is programming with declarations, i.e. declarative sentences.声明式编程是使用声明(即声明性语句)进行编程。The declarative property is where there can exist only one possible set of statements that can express each specific modular semantic. The imperative property is the dual, where semantics are inconsistent under composition and/or can be expressed with variations of sets of statements.声明性属性是只能存在一组可能表达每个特定模块化语义的语句的地方。 命令属性是双重的,其中语义在组成上是不一致的和/或可以用语句集的变体来表达。

Declarative languages contrast with imperative languages which specify explicit manipulation of the computer’s internal state; or procedural languages which specify an explicit sequence of steps to follow.

声明性语言与命令性语言形成对比,命令性语言指定了对计算机内部状态的显式操作 ; 或指定要遵循的明确步骤顺序的程序语言。

In computer science, declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow.在计算机科学中,声明性编程是一种编程范例,用于表达计算的逻辑而不描述其控制流程。