对于一些功能比较复杂的函数,须要将不少配置项做为参数传入,这时候传统的位置参数表就不太方便了,由于对于配置项参数,咱们每每会设置默认值,但愿使用者无需按顺序传入全部参数,而只要指明哪几个参数须要特别配置。前端
好比一个简单的字符串格式化函数,除了必需的传入值 value
外,有三个配置项:git
indent
:缩进github
caseMode
:大小写面试
callback
:转换完成后的回调编程
前端代码中应该如何定义呢?bash
咱们先看看用 JavaScript 的状况。编程语言
若是咱们按照最原始的定义方法:函数
function transform(value, indent, caseMode, callback) {
...
}
复制代码
那么使用者就必须记住全部配置参数的位置,要是只想设置 caseMode
,须要写成以下尴尬的形式:spa
transform('someStr', undefined, 'upper')
复制代码
事实上不少 JavaScript 内置函数就是采用的这种方式,使用者很难记住全部的位置参数,所以[1, 2, 3].map(parseInt)
才会成为“经典”面试题。code
不少现代编程语言,好比 Dart 或 Python ,增长了“命名参数”这一特性,解决了参数与参数名对应的问题:
transform('someStr', caseMode: 'upper')
复制代码
JavaScript 没有命名参数这一特性,早期实践中每每经过“配置对象参数“的方式,达到相似的效果:
function transform(value, cfg) {
...
if(cfg.caseMode) ...
}
复制代码
对象参数的缺点是源码中 cfg
的配置项不够直观,默认值设置比较麻烦,类型检查约束性不够。
如今配合上 ES6 的解构赋值和函数默认值,直观性和默认值能够解决了:
function transform(value, {
indent = 2,
caseMode = 'upper',
callback,
} = {}) {
...
}
复制代码
不过约束性仍是不够,不能实现“必选参数”、“可选参数”的功能。
这时候就要 TypeScript 上场了。
除了类型检查外,TypeScript 能够对必选参数进行空值检查,而后再经过?:
手动设置可选参数:
function transform(value: string, {
indent = 2,
caseMode = 'upper',
callback,
}:{
indent?: number,
caseMode?: string,
callback?: (rst: string) => void,
} = {}) {
...
}
复制代码
这就是 TypeScript 中比较完整的一个列子,实现了命名参数、可选参数,参数默认值的功能,使用时:
transform('someStr', { caseMode: 'upper' })
复制代码
在以上的定义中,“命名参数”用上了 {}: {}={}
的结构进行定义,格式上要分红两段,另外因为本质上是个对象参数,外面仍是不能忘了大括号的,写法略有些冗长,可是 TypeScript 的团队 表示 因为保留位置限制、表达式解析等种种缘由,目前不会加入真正的“命名参数”特性,所以目前只能这样写。