我有一个带有必需参数(A),一些可选参数(B,C)和其他参数(Z)的函数
import io
import os
from google.cloud import vision
client = vision.ImageAnnotatorClient()
response = client.annotate_image({
'image': {'source': {'image_uri': '<IMAGE_URI>'}},
'features': [{'type': vision.enums.Feature.Type.SAFE_SEARCH_DETECTION},
{'type': vision.enums.Feature.Type.LABEL_DETECTION}]
})
print(response)
在某些情况下,我想在不指定可选参数的情况下调用该函数,但仍然指定其余参数“ Z”
const doTheThing = (a, b = 'B', c = 'C', ...z) => {
console.log(a, b, c, z);
}
预期输出:
doTheThing('A', ...'Z');
不幸的是,我得到以下信息:
'A', 'B', 'C', 'Z'
我该如何解决这个问题?
答案 0 :(得分:1)
JavaScript不允许提供命名参数或任何形式的参数跳过,因此无法使用当前形式的函数来执行所需的操作。不过,这里有一些替代方法:
代替接受多个参数
func = (a, b, c) => { /* operate with parameters */ }
func("One", "Two", "Three")
您的函数将改为接受一个对象
func = config => { /* operate with config */ }
func({a: "One", b: "Two", c: "Three"})
这是JavaScript中的常见模式,因为它允许您几乎命名变量,并且不需要以正确的顺序传递它们。它可以轻松传递大量变量,也可以使其也很容易默认它们。
const doTheThing = (config) => {
const defaultProperties = {
b: "B",
c: "C"
}
const {a, b, c, ...rest} = Object.assign({}, defaultProperties, config);
const z = Object.values(rest); //extract their values, otherwise you get an object
console.log(a, b, c, z);
}
doTheThing({a: "A", x: "X", y: "Y", z: "Z"});
与rest参数一起使用时有点笨拙,但并非不可行。
但是,这确实意味着,如果有很多参数,则可能很难看清可以传递哪些参数以及需要哪些参数。
您将创建一个构建器对象-它用于保存值,直到调用final方法为止,此时将接受所有参数并一次性构造一个对象。
这是更多面向对象语言处理大量参数的方式,您甚至可以选择其中的一些参数。在JavaScript中看到这样定义的构建器并不是很常见,但是也不太奇怪。如果您已经使用类,甚至使用TypeScript,则可能更合适。
class DoTheThingBuilder {
constructor() {
this.a = null;
this.b = "B";
this.c = "C";
this.z = null;
}
withA(a) {
this.a = a;
return this;
}
withB(b) {
this.b = b;
return this;
}
withC(c) {
this.c = c;
return this;
}
withEverythingElse(...z) {
this.z = z;
return this;
}
doTheActualThing() {
const {a, b, c, z} = this;
console.log(a, b, c, z);
}
}
const builder = new DoTheThingBuilder();
builder
.withA("A")
.withEverythingElse("X", "Y", "Z")
.doTheActualThing();
如您所见,对于某些简单任务而言,这可能非常冗长。对于这个示例来说,这是一个很大的矫kill过正,但是也许在实际使用中,您可能会发现它有所帮助。
我已经偏离了通常的方法-通常,您将设置构建器所需的所有参数,最后调用.build()
来构建对象。在这种情况下,我基本上将build
重命名为doTheActualThing
并执行了该功能。
currying的概念非常简单-而不是拥有一个可以接受多个参数的函数
func = (a, b, c) => { /* operate with parameters */ }
您有一个带有一个参数的函数,该函数返回一个带有第二个参数的函数,返回另一个函数,依此类推,直到满足所有参数为止,然后执行完整的函数。
func = a => b => c => { /* operate with parameters */ }
在许多方面,这与OO Builder模式的功能等效。
const doTheThing = (a) =>
(b = "B") =>
(c = 'C') =>
(...z) => console.log(a, b, c, z);
doTheThing("A")()()("X", "Y", "Z");
这样,您可以通过不提供第二个和第三个参数来跳过它们,从而获得默认值。它也比生成器短。但是,阅读该功能可能有点奇怪。
答案 1 :(得分:0)
那是不可能的,而且很容易出错。命名参数的关键是要知道它们是什么以及它们以什么顺序出现。
使用object作为函数参数可以实现类似的目的:
const doTheThing = ({ a, b = "B", c = "C", others = {} }) => {
const params = { a, b, c, ...others }; // this will merge your parameters into one object
console.log(params);
}
doTheThing({ a: "A", others: { z: "Z" }});
这将记录A,B,C,Z。演示:https://codepen.io/tomekbuszewski/pen/jQqmNL?editors=0011