在JavaScript中,有没有一种方法可以在函数调用中提供命名参数?

12 浏览
0 Comments

在JavaScript中,有没有一种方法可以在函数调用中提供命名参数?

比如说,C# 允许使用命名参数,例子如下:

calculateBMI(70, height: 175);

我觉得这很有用。我怎样在 JavaScript 中实现类似的效果?

我尝试过像下面这样做:

myFunction({ param1: 70, param2: 175 });
function myFunction(params){
  // 检查 params 是否是一个对象
  // 检查我需要的参数是否非空
  // 啦啦啦
}

但感觉有些别扭。有没有更简单的方法?

0
0 Comments

在JavaScript中,是否有一种方法可以在函数调用中提供命名参数?

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 deleteUser(user) { ... }deleteUser({name: ...})就不起作用,因为对象被解释为“命名参数对象”。你必须写成deleteUser({user: {name: ...}})

我有一个函数func(a,b,c,d,e, f=false)在许多地方使用,我调用函数func(a,b, {f: true}),但f仍然为false,请问有人能帮忙吗?

对于顶部的ES2015及以后版本,请详细解释一下function myFunction({param1, param2}={}) { ... }。对我来说,它看起来像是将一个空数组或对象赋值给一个具有两个成员的数组或对象(通常情况下,这种赋值是不起作用的),然后将这个不起作用的赋值的结果作为单个参数提供给myFunction

0
0 Comments

JavaScript中是否有一种方法可以在函数调用中提供命名参数?

答案是:没有。对象的方法是JavaScript对此的回答。只要您的函数期望一个对象而不是单独的参数,这种方式就没有问题。

现在有了es6:2ality.com/2011/11/keyword-parameters.html

这绝对是一个公正的答案 - “命名参数”是一种语言特性。在没有这样的特性的情况下,对象方法是最好的替代方案。

使用对象方法时,如果我们必须重命名一个参数名称,那么重构可能会成为一个问题。我们需要去每个调用中更改参数对象;很有可能会忽略一个调用并造成运行时问题。

0
0 Comments

原因:很多开发人员在JavaScript中调用函数时使用“传递对象”的技巧,以实现命名参数的效果。但是,这种方法在使用大多数IDE时存在问题。因为IDE只会给出一个类型提示,无法知道应传入arg1对象的参数和类型。

解决方法:一种解决方法是将参数的名称作为局部变量声明,以避免全局命名空间的污染。另一种解决方法是使用ES6中的对象解构语法来实现类似命名参数的效果。新的浏览器大多支持这种语法,并且大多数IDE也支持该语法,并提供良好的参数提示支持。

在TypeScript中,可以使用相同的语法或接口来实现类似的效果。需要注意的是,这种技术无法更改参数的顺序。

2022年的更新:JavaScript现在可以使用ES6中的对象解构来实现类似命名参数的效果。大多数新的浏览器都支持这个特性。在TypeScript中,也可以使用相同的语法或接口来实现类似的效果。

以前在JavaScript中实现命名参数的方法存在一些问题,无法在IDE中获得准确的参数提示。现在可以使用对象解构语法或TypeScript来实现类似的效果,大多数IDE也支持这种语法,并提供良好的参数提示支持。这种方法可以更方便地编写新代码,并且在维护代码时能够清楚地看到参数的值和名称。

0