![计算机程序的构造和解释(JavaScript版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/951/50417951/b_50417951.jpg)
1.1.4 复合函数
我们已经介绍了JavaScript里的一些元素,它们必然也会出现在任何一种强大的程序设计语言里,包括:
●数和算术运算是基本的数据和函数。
●组合式的嵌套提供了一种把多个操作组织起来的方法。
●常量声明是一种受限的抽象手段,其功能就是为名字关联值。
现在我们来学习函数声明,这是一种威力更强大的抽象技术,通过它可以给复合操作确定一个名字,而后就可以把它作为一个单元来引用。
我们从如何表述“平方”的概念开始。我们可能说“求某个东西的平方,就是用它自身去乘它自身”。在我们的语言里,这件事应该表述为:
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/29_01.jpg?sign=1739563503-vGh4JOsHXRd5swrJFuq9eLKv1VwReBgu-0-52433b141a56c1f9f535d153748709a2)
可以按如下方式理解这一描述:
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/29_02.jpg?sign=1739563503-iVufPZgBNWJ2zXzIQua0MKBEXmxjdQoE-0-b6f50707fdb8d9e8cb3b4889eede62fa)
这样我们就有了一个复合函数,它还被命名为square。这个函数表示把一个东西乘以其自身的操作。被乘的东西给定了一个局部名x,它扮演着与自然语言里的代词同样的角色。求值这一声明的结果就是创建出一个复合函数,并把它关联于名字square[6]。
最简单的函数声明的形式是:
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/29_03.jpg?sign=1739563503-nXw0bJpPF1ons9CHF1FP4AhqgJ56bDbZ-0-c27ba90b97ae5ead46da0e61d3126688)
其中的name是一个名字,函数的定义将在环境中关联于这个名字[7]。parameters(形式参数)是一些名字,它们被用在函数体里,表示要求引用在应用这个函数时提供的各个实参。这些parameters写在一对括号里,用逗号分隔,就像所声明的函数被实际调用时的写法。在最简单的形式里,这里的body就是一个返回语句,由关键字return和一个返回表达式构成[8]。在函数应用时,声明中的形式参数被与之对应的实参取代,返回表达式的执行生成函数应用的值。与常量声明和表达式语句一样,返回语句最后也需要有分号。
声明了square之后,我们就可以在函数应用表达式里使用它。我们可以给这种表达式加上分号,将其转变为一个语句:
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/29_04.jpg?sign=1739563503-GkonLfouMqmpDU6HImL1ir1JEHOb0tis-0-2a92a1d0311e52dbdd8bb8a3d63c9edd)
除了运算符组合式,函数应用是我们遇到的第二种组合表达式,它们同样可用于构造更大的表达式。函数应用的一般形式是:
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/29_05.jpg?sign=1739563503-aBB3weDqAaid32VmATPvG7zGCgHdUvRM-0-d9f3afd2e4d9dba259b563314035daea)
应用中的function-expression(函数表达式)描述希望应用的函数,要求将其应用于逗号分隔的那些argument-expression(实参表达式)。在求值一个函数应用式时,解释器将按下面的过程工作,类似于1.1.3节描述的运算符组合式的求值过程:
需要求值一个函数应用式时,按下面的方式工作:
1.求值应用式中的各个子表达式,即其中的函数表达式和各个实参表达式。
2.把得到的函数(也就是函数表达式的值)应用于那些实参表达式的值。
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/30_01.jpg?sign=1739563503-EUNdfPpoi19AGnrB8jFm22wNnwGoB1dH-0-e9858c8923a3981f2e117f9f0b38b8d4)
这里的实参表达式本身又是组合式,即为运算符组合式2+5。
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/30_02.jpg?sign=1739563503-HG86DTh9a3iKSb9UudwYJAvGZlWiAwl7-0-98798c17e6bc9fe9ebd90cf5490f637c)
很自然,实参表达式同样也可以是函数应用表达式。
我们还可以用square作为基本构件去声明其他函数。举例说,x2+y2可以描述为:
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/30_03.jpg?sign=1739563503-x0BuH55patjZacn2saeuY2z9bX6R5IgD-0-b4cec9145312b1421c33fc05d32a300f)
现在我们很容易声明一个函数sum_of_squares[9],给它两个数作为实参,它就能给出这两个数的平方和:
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/30_04.jpg?sign=1739563503-32YmdAru8uig48JmnAtb5cJwgJ034TAM-0-7654ba661885b7b8ab4e17c396b1c499)
现在我们又可以用sum_of_squares作为构件,进一步去构造其他函数了:
![](https://epubservercos.yuewen.com/1E97F9/29686461304596906/epubprivate/OEBPS/Images/30_05.jpg?sign=1739563503-qX8NOnjBeYkvSzzi9KGTViYl1X5k2YcU-0-b8049b2b9d7b2ad1e6e1c96990e31d05)
除了复合函数之外,每个JavaScript环境都提供了一些基本函数,它们被构筑在解释器里,或者可以从函数库装入。除了为各个运算符提供相应的基本函数,本书使用的JavaScript环境还包括了另外一些基本函数,例如函数math_log,它计算实参的自然对数值[10]。基本函数的使用方式与复合函数一样,math_log(1)将得到数值0。实际上,如果只看上面给出的sum_of_squares的声明,我们根本没办法分辨其中的square究竟是直接构筑在解释器里,或是从程序库装入,还是通过声明定义的复合函数。