我发现C#中的命名参数特性在某些情况下非常有用。
calculateBMI(70, height: 175);
如果我想在JavaScript中使用这个,我可以使用什么呢?
我不想要的是:
myFunction({ param1: 70, param2: 175 });
function myFunction(params){
// Check if params is an object
// Check if the parameters I need are non-null
// Blah blah
}
我已经用过的方法。还有别的办法吗?
我可以用任何图书馆来做这个。
ES2015及更高版本
在ES2015中,参数析构可以用来模拟命名参数。它将要求调用方传递一个对象,但如果还使用默认参数,则可以避免函数内部的所有检查:
myFunction({ param1 : 70, param2 : 175});
function myFunction({param1, param2}={}){
// ...function body...
}
// Or with defaults,
function myFunc({
name = 'Default user',
age = 'N/A'
}={}) {
// ...function body...
}
ES5
有一种方法可以接近您想要的结果,但它基于function.prototype.toString
[ES5]的输出,该输出在某种程度上依赖于实现,因此可能不是跨浏览器兼容的。
其思想是从函数的字符串表示形式中解析参数名称,以便您可以将对象的属性与相应的参数相关联。
这样,函数调用就可以看起来像
func(a, b, {someArg: ..., someOtherArg: ...});
其中a
和b
是位置参数,最后一个参数是具有命名参数的对象。
例如:
var parameterfy = (function() {
var pattern = /function[^(]*\(([^)]*)\)/;
return function(func) {
// fails horribly for parameterless functions ;)
var args = func.toString().match(pattern)[1].split(/,\s*/);
return function() {
var named_params = arguments[arguments.length - 1];
if (typeof named_params === 'object') {
var params = [].slice.call(arguments, 0, -1);
if (params.length < args.length) {
for (var i = params.length, l = args.length; i < l; i++) {
params.push(named_params[args[i]]);
}
return func.apply(this, params);
}
}
return func.apply(null, arguments);
};
};
}());
您可以将其用作:
var foo = parameterfy(function(a, b, c) {
console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);
});
foo(1, 2, 3); // a is 1 | b is 2 | c is 3
foo(1, {b:2, c:3}); // a is 1 | b is 2 | c is 3
foo(1, {c:3}); // a is 1 | b is undefined | c is 3
foo({a: 1, c:3}); // a is 1 | b is undefined | c is 3
演示
这种方法有一些缺点(您已经被警告过了!):
undefined
(这与根本没有值不同)。这意味着您不能使用arguments.length
来测试传递了多少个参数。您也可以使用一个接受函数和各种值作为参数的函数,而不是使用一个创建包装器的函数,例如
call(func, a, b, {posArg: ... });
或者甚至扩展function.prototype
,以便您可以执行以下操作:
foo.execute(a, b, {posArg: ...});
不-对象方法是JavaScript对此的回答。如果函数需要一个对象而不是单独的参数,那么这是没有问题的。
一段时间以来,这个问题一直是我最讨厌的问题。我是一个经验丰富的程序员,掌握多种语言。我最喜欢的语言之一是Python。Python支持命名参数,没有任何花招。。。。自从我开始使用Python(一段时间以前),一切都变得更容易了。我相信每种语言都应该支持命名参数,但事实并非如此。
很多人说,只要使用“传递一个对象”技巧,就可以命名参数。
/**
* My Function
*
* @param {Object} arg1 Named arguments
*/
function myFunc(arg1) { }
myFunc({ param1 : 70, param2 : 175});
效果很好,除了。。。。当谈到大多数IDE时,我们很多开发人员都依赖IDE中的类型/参数提示。我个人使用PHP Storm(以及JetBrains的其他IDE,如用于python的PyCharm和用于Objective C的AppCode)
使用“传递对象”技巧的最大问题是,当您调用函数时,IDE会给您一个类型提示,仅此而已。。。我们如何知道arg1对象中应该包含哪些参数和类型?
所以。。。“传递一个物体”的把戏对我不起作用。。。实际上,在我知道函数需要什么参数之前,必须查看每个函数的docblock,这会让我更加头疼。。。。当然,当您维护现有代码时,它是很好的,但是对于编写新代码来说,它就很糟糕了。
嗯,这是我用的技术。。。。现在,它可能会有一些问题,一些开发人员可能会告诉我我做得不对,当涉及到这些事情时,我有一个开放的心态。。。我总是愿意寻找更好的方法来完成任务。因此,如果这个技术有问题,欢迎提出意见。
/**
* My Function
*
* @param {string} arg1 Argument 1
* @param {string} arg2 Argument 2
*/
function myFunc(arg1, arg2) { }
var arg1, arg2;
myFunc(arg1='Param1', arg2='Param2');
这样,我两全其美。。。新代码很容易编写,因为我的IDE给了我所有适当的参数提示。。。而且,在稍后维护代码时,我不仅可以一眼看到传递给函数的值,还可以看到参数的名称。我看到的唯一开销是将参数名称声明为局部变量,以避免污染全局名称空间。当然,这是一些额外的键入,但与在编写新代码或维护现有代码时查找文档块所花费的时间相比,这是微不足道的。