阿瑞斯的BLOG

JavaScript函数的设计

关键词
黑匣子 抽象 封装 参数个数检查 参数类型检查

函数的核心理念——抽象和封装过程

封装过程:指的是用户只需知道函数名,如何正确的传递参数以及返回值就够了,而内部的逻辑用户无需知道。

抽象:借助抽象,我们才能不关心底层具体的实现/计算过程,而直接在更高层上思考问题。

而函数就是抽象的方式,一个函数就是一个一个完整的行为,函数体内部的语句在执行的时候,函数内部通过条件判断和循环就可以完成非常复杂的逻辑。

函数的执行过程

输入(传参)——计算/处理 ——输出(返回结果,如果有)

函数就是一段完整的代码,函数在执行的过程中,如果没有return语句(函数结尾如果没有return语句就是隐含 return undefined),控制权无法交回被调用的代码。一旦执行到return时,函数就执行完毕,并将结果返回。

ES6中的Generator函数除外,Generator函数的yield类似return,可以返还控制权。

JS中的函数

  1. JavaScript中函数定义参数时没有指定参数的数据类型

  2. JavaScript中的函数不会对参数arguments进行类型检查

  3. JavaScript中的函数不会对arguments进行个数检查

  4. JavaScript中函数没有重载

对比JAVA的函数

1
2
3
public String getRecord(int key) {
return db[key];
  • 修饰符public修饰了函数getRecord的可访问性

  • String说明了存在返回值并且说明了返回值类型

  • int key说明了参数类型和参数名字

JAVA函数的定义

1、支持重载

2、定义函数时就可以看到函数的访问性(访问控制修饰符)

3、定义函数时就可以看到函数的返回值类型

4、定义函数时就可以看到函数的参数类型

对比Python函数

调用函数的时候,如果传入的参数数量不对,会报TypeError的错误,并且Python会明确地告诉你:abs()有且仅有1个参数,但给出了两个:

1
2
3
4
>>>abs(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: abs() takes exactly one argument (2 given)

如果传入的参数数量是对的,但参数类型不能被函数所接受,也会报TypeError的错误,并且给出错误信息:str是错误的参数类型:

1
2
3
4
>>> abs('a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

Python函数调用

1、拥有对参数个数检查的机制

2、拥有对参数类型检查的机制

集百家所长编写健壮的JS函数

因为js函数没有对实参进行检查的机制,所以我们编写函数就要自己模拟实现这些机制

从Python中得到的感悟

首先,对参数的个数进行检查

利用arguments参数判断实际传入参数的个数,这也就是说即使函数没有定义参数,也可以拿到参数的值,也是很多js库常使用的手段

  • 实现:可选”参数”
1
2
3
4
5
6
// 接收2-3个参数,参数b是可选参数,如果只传2个值,b默认为null
function abc(a, b, c) {
if(arguments.length === 2) {
//实际拿到的是a和b,c为undefined
c = b; // 把b赋给c
b = null; // b变为默认值

要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值。

其次,检查参数的数据类型

使用条件判断的方式判断参数的是否传递,以及参数是否是期望的值

1
2
3
4
5
6
7
8
9
10
function log(x, y) {
if(typeof y !== 'string') { //检测参数的数据类型
y = 'World';
}
}
console.log(x, y);
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

从JAVA中得到的感悟

JAVA中的函数从函数的定义就可以看到函数的参数类型,是否有返回值和返回值类型

所以为了编写可维护的JavaScript函数,我们可以利用注释和规范的命名实现对函数的描述。

  • 利用函数名描述函数的功能
  • 利用参数名描述参数是什么,利用注释描述参数的数据类型
  • 利用返回值描述结果是什么,利用注释描述返回值的数据类型
  • 或者写一段完整注释包括:描述函数的目的,功能,参数和参数类型,返回值和返回值类型

模拟函数重载

函数重载:函数名相同,参数的个数和类型不同,实现不同的功能。

模拟重载:利用条件判断判断参数的个数和参数的类型,来实现重载。

参考:

廖雪峰·Python教程