ES2015及以后版本
在ES2015中,参数解构可用于模拟命名参数。这需要调用者传递一个对象,但如果你还使用默认参数,则可以避免在函数内部进行的所有检查:
myFunction({ param1 : 70, param2 : 175});
function myFunction({param1, param2}={}){
}
function myFunc({
name = 'Default user',
age = 'N/A'
}={}) {
}
ES5
有一种方法可以接近你想要的效果,但它基于Function.prototype.toString
[ES5]的输出结果,这在某种程度上依赖于实现,因此可能不跨浏览器兼容。
思路是从函数的字符串表示中解析参数名称,以便将一个对象的属性与对应的参数关联起来。
然后函数调用可能会像这样:
func(a, b, {someArg: ..., someOtherArg: ...});
其中a
和b
是位置参数,而最后一个参数是具有命名参数的对象。
例如:
var parameterfy = (function() {
var pattern = /function[^(]*\(([^)]*)\)/;
return function(func) {
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: ...});
Function
ж— жі•жӣҙж”№JavaScriptзҡ„ж ёеҝғиҜӯжі•гҖӮ - GarethcalculateBMI (70,/*height:*/ 175);
,(2)提供一个对象calculateBMI(70, {height: 175})
,或者(3)使用一个常量const height = 175; calculateBMI(70, height);
。 - tim-montague