为什么编程语言重要
在计算技术发展伊始,并没有编程语言这个概念。程序看起来就像这样:
00110001 00000000 0000000000110001 00000001 0000000100110011 00000001 0000001001010001 00001011 0000001000100010 00000010 0000100001000011 00000001 0000000001000001 00000001 0000000100010000 00000010 0000000001100010 00000000 00000000
该程序计算数字 1~10 之和,并打印出结果:1+2+...+10=55。该程序可以运行在一个简单的机器上。在早期计算机上编程时,我们需要在正确的位置设置大量开关阵列,或在纸带上穿孔并将纸带输入计算机中。你可以想象这个过程是多么冗长乏味且易于出错。即便是编写非常简单的程序,也需要有经验的人耗费很大精力才能完成。编写复杂的程序则更是难上加难。
当然了,手动输入这些晦涩难懂的位序列(1 和 0)来编写程序的确能让程序员感到很有成就感,而且能给你的职业带来极大的满足感。
在上面的程序中,每行都包含一条指令。我们可以用中文来描述这些指令:
将数字 0 存储在内存地址中的位置 0。
将数字 1 存储在内存地址的位置 1。
将内存地址的位置 1 中的值存储在内存地址的位置 2。
将内存地址的位置 2 中的值减去数字 11。
如果内存地址的位置 2 中的值是 0,则跳转到指令 9。
将内存地址的位置 1 中的值加到内存地址的位置 0。
将内存地址的位置 1 中的值加上数字 1。
跳转到指令 3。
输出内存地址的位置 0 中的值。
虽说这已经比一大堆位序列要好读了许多,但仍然不清晰。使用名称而不是数字用于指令和存储位置有所帮助:
Set “total” to 0.Set “count” to 1.[loop]Set “compare” to “count”.Subtract 11 from “compare”.If “compare” is zero, continue at [end].Add “count” to “total”.Add 1 to “count”.Continue at [loop].[end]Output “total”.
现在你能看出该程序是如何工作的吗?前两行代码初始化两个内存位置的值:total用于保存累加计算结果,而count则用于记录当前数字。你可能觉得compare的那行代码看起来有些奇怪。程序想根据count是否等于 11 来决定是否应该停止运行。因为我们的机器相当原始,所以只能测试一个数字是否为 0,并根据它做出决策。因此程序用名为compare的内存位置存放count–11的值,并根据该值是否为 0 决定是否跳转。接下来两行将count的值累加到结果上,并将count加 1,直到count等于11为止。
下面使用 JavaScript 重新编写了上面的程序:
let total = 0, count = 1;while (count <= 10) {total += count;count += 1;}console.log(total);// → 55
这个版本的程序得到了一些改进。更为重要的是,我们再也不需要指定程序如何来回跳转了,而是由while结构负责完成这个任务。只要我们给予的条件成立,while语句就会不停地执行其下方的语句块(包裹在大括号中)。而我们给予的条件是count<=10,意思是“count小于等于 10”。我们再也不需要创建临时的值并将其与 0 比较,那样的代码十分烦琐。编程语言的一项职责就是,能够帮助我们处理这些烦琐无趣的逻辑。
在程序的结尾,也就是while语句结束后,我们使用console.log操作来输出结果。
最后,我们恰好有range和sum这类方便的操作。下面代码中的range函数用于创建数字集合,sum函数用于计算数字集合之和:
console.log(sum(range(1, 10)));// → 55
我们可以从这里了解到,同一个程序的长度可长可短,可读性可高可低。第一个版本的程序晦涩难懂,而最后一个版本的程序则接近于人类语言的表达方式:将 1~10 范围内的数字之和记录下来(我们会在后面的章节中详细介绍如何编写sum和range这样的函数)。
优秀的编程语言可以为开发人员提供更高层次的抽象,使用类似于人类语言的方式来与计算机进行交互。它有助于省略细节,提供便捷的积木(比如while和console.log),允许你定义自己的积木(比如sum和range函数),并使这些积木易于编写。。
