指令式编程 VS 声明式编程

概括地说,我们可以有两种编写代码的方式:指令式和声明式。

我们可以定义如下:

指令式编程:告诉机器该如何做,并得到自己想要的结果。

声明式编程:告诉机器您想得到什么,让机器自己计算该如何做。

指令式编程和声明式编程的例子

举一个简单的例子,假设我们想让数组中的每个值变为原来的2倍。

指令式编程的代码可以如下:

var numbers = [1,2,3,4,5]var doubled = []for(var i = 0; i < numbers.length; i++) {  var newNumber = numbers[i] * 2  doubled.push(newNumber)}console.log(doubled) //=> [2,4,6,8,10]

我们遍历整个数组,取出每个元素,乘以2,然后把新值放到新数组中,直到完成。

一种声明式的编程方式可以使用Array.map,如下:

var numbers = [1,2,3,4,5]var doubled = numbers.map(function(n) {  return n * 2})console.log(doubled) //=> [2,4,6,8,10]

map根据旧数组返回新的数组,在这个例子中,通过把旧数组中的元素传入到map(function(n) { return n*2 }中,返回一个新数组,新数组的每个值都是相对应的旧数组的值的2倍。

map函数的作用是抽象出遍历数组的过程,让我们更关注于我们想得到什么。注意,我们传入到map中的函数是纯净的。不能有任何副作用(改变其他额外的状态),它只是拿到一个数,并把它变成2倍。

对于数组,这里还有其他一些常见的声明式抽象函数。比如说,为了对数组中所有的元素求和,我们可以这么做:

var numbers = [1,2,3,4,5]var total = 0for(var i = 0; i < numbers.length; i++) {  total += numbers[i]}console.log(total) //=> 15

或者我们可以使用声明式函数reduce:

var numbers = [1,2,3,4,5]var total = numbers.reduce(function(sum, n) {  return sum + n}, 0);console.log(total) //=> 15

reduce利用给定的函数将数组遍历计算出一个值。它将这个函数应用到数组中的每个元素。在每次调用中,第一个参数(例子中的sum)是前一个元素调用函数后得出的结果,第二个参数(n)是当前元素。所以,在这个例子中,每一步,都把当前数组元素n加到sum中,这样,最后我们就能得到整个数组的和。

同样,reduce为我们抽象了循环遍历和状态管理方面的事情,给了我们遍历数组计算出一个值的通用方法。我们需要做的就是明确我们想要什么。

很奇怪?

我保证,如果您之前没见过map或者reduce,您一定会感觉到奇怪。作为程序员,我们总是很习惯指定如何让事情发生,“遍历数组”,“如果怎么样然后怎么样”,“用新值更新这个变量”。既然我们已经知道如何告诉机器该怎么做,为什么还要学习这个看起来有点奇怪的抽象呢?

在许多情况下,指令式代码是好的。当我们编写业务逻辑时,我们通常不得不编写大部分必需的代码,因为在我们的业务逻辑中不存在更通用的抽象。

但是如果我们花时间去学习(或构建!)声明式的抽象方法,在编写代码时,我们就可以使用一些强大的快捷方式。首先,我们通常会写得越来越少,这是一个速见成效的胜利。然后,我们也可以在一个更高的层次思考问题,站在云端思考我们想要发生什么,而不是陷在泥里思考如何使它发生。

SQL

您可能没有意识到,但是在SQL中,您已经使用过声明式编程了。

您可以把SQL看作一种用于处理数据集的声明式查询语言。您是否用SQL写过整个应用?可能没有。但是对于处理相关联的数据集,它会非常强大。

做一个查询:

SELECT * from dogsINNER JOIN ownersWHERE dogs.owner_id = owners.id

想象一下您用指令式编程来写这段逻辑:

//dogs = [{name: 'Fido', owner_id: 1}, {...}, ... ]//owners = [{id: 1, name: 'Bob'}, {...}, ...]var dogsWithOwners = []var dog, ownerfor(var di=0; di < dogs.length; di++) {  dog = dogs[di]  for(var oi=0; oi < owners.length; oi++) {    owner = owners[oi]    if (owner && dog.owner_id == owner.id) {      dogsWithOwners.push({        dog: dog,        owner: owner      })    }  }}}

我并不是说SQL很容易理解,或者当您第一次看到时就很轻松地明白它,但是相比于那段复杂的代码,它已经简洁很多了。

但是它不仅更简短而且更容易阅读,SQL还给了我们许多其他好处。因为我们已经抽象了具体的实现方法,我们可以只关注我们想要什么,然后让数据库优化具体实现步骤。

如果我们没有使用它,我们自己的代码将会很慢,因为我们必须要为列表中的每只dog遍历整个owners数组。

但是在SQL代码的例子中,我们可以让数据库来自己实现如何返回给我们正确的结果。如果使用索引有意义(假设我们已经建立了),数据库就会这么做,这会提升很大的性能。

如果此次查询在一秒前就执行过,就可以直接从缓存中读取。通过放手让计算机自己决定实现方式,我们只需要稍微改变一下认知,就可以得到巨大的好处。

来源:掘金

 


另外如果你想更好的提升你的编程能力,学好C语言C++编程!弯道超车,快人一步!笔者这里或许可以帮到你~

UP在主页上传了一些学习C/C++编程的视频教程,有兴趣或者正在学习的小伙伴一定要去看一看哦!会对你有帮助的~

分享(源码、项目实战视频、项目笔记,基础入门教程)

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

 

编程学习:

编程学习:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值