函数的组件
函数具有三个语法组件, 这三个语法组件构成了函数值
- 参数列表 (list)
- 函数体 (body)
- 返回值 (return value)
- 环境
可以做一个有趣的类比: 将以上三个组件打包成某个"电路模块"(或者是某种电子器件的样板)
在你去给这个电路模块供电的时候, 就需要使用一根"电线", 并需要将它连接到电路模块中的电线端子, 这根电线构成了一个信道,将该电路模块中的这些电线端子称之为"参数", 同时将电线连接到电路模块的电线端子这一行为称之为"绑定"。
以下面这段代码中函数add进行举例
var add = function (a, b) {
return a + b;
}
add
函数就是一块电路样板, 这块电路样板就静静的躺在那里, 当我们调用它时这块模版就会编程动态的可执行结构。
add(1, 2)
外部电线1, 2连接到电路实例上的电线端子上,然后 (将值1绑定a, 值2绑定到b), 最终电流流经导线, 流到x + y, 电流通过这根电线到达另外一端, 此时如果电线导电性良好, 两头的电压应该几乎相等。这个使得电路模块运转起来这个过程我们叫做"函数调用"。
(1.a), (2.b)
所以函数是一个模版,函数调用是创建一个模版的实例, 变量是作为一个电线管道连接到电路模块上面去, 为这个电路模块输送值, 最终电路模块得以运行, 为我们输送出来一个值。
面向对象
上文说过函数是一个模版, 那么类是不是也是一个模版呢?我想是的,
- 首先类的端子来自于构造函数
- 其次类中的一些逻辑来自于方法
- 其次类的实例来自于对象的构建
从上面这个三点来看, 函数和类并没有什么不同, 但是还是有点不同的就是, 面向对象为用户提供了一个界面, 这个界面屏蔽了很多细节, 但是为外部提供了接口。
struct Point{
int x;
int y;
fun getX() {
return x;
}
fun getY() y;
}
Point.getX();
Point.y;
就像下面这种我们是不会发现这个x, y具体的实现的, 因为我们封装了它们。
Q&A
问: 为什么要使用"电线"和"电路"模块的角度来解释函数原因有2
答: 我认为每一个程序都是一台机器(machine)的描述, 我们程序员需要做的事情就是去模拟这台机器的运行。如果你知道什么是AST树, 你就会发现其实树结结构的节点和电路模块有着异曲同工之妙, 连接两个节点直接的线, 其实就是"导线"。而每个节点可以看做是一个电路模块。