Javascript 如何以编程方式设置函数的长度

Javascript 如何以编程方式设置函数的长度,javascript,Javascript,说明“预期”参数列表的长度: console.log((function () {}).length); /* 0 */ console.log((function (a) {}).length); /* 1 */ console.log((function (a, b) {}).length); /* 2 etc. */ 但是,它是一种只读方法: f = function (a) {}; alert(f.length); // 1 f.length = 3; alert(f.length)

说明“预期”参数列表的长度:

console.log((function () {}).length);  /* 0 */
console.log((function (a) {}).length); /* 1 */
console.log((function (a, b) {}).length); /* 2 etc. */
但是,它是一种只读方法:

f = function (a) {};
alert(f.length); // 1
f.length = 3;
alert(f.length); // 1
有没有办法以编程方式设置该长度?到目前为止,我最接近的方法是使用函数构造函数:

f = new Function("a,b,c", "/* function body here */");
f.length; // 3

然而,使用函数本质上与
eval
相同,我们都知道这有多糟糕。我还有什么其他选择吗?

现在,这里是我能想到的最好的解决方案

makeFunc = function (length, fn) {
    switch (length) {
    case 0 : return function () { return fn.apply(this, arguments); };
    case 1 : return function (a) { return fn.apply(this, arguments); };
    case 2 : return function (a,b) { return fn.apply(this, arguments); };
    case 3 : return function (a,b,c) { return fn.apply(this, arguments); };
    case 4 : return function (a,b,c,d) { return fn.apply(this, arguments); };
    case 5 : return function (a,b,c,d,e) { return fn.apply(this, arguments); };
    case 6 : return function (a,b,c,d,e,f) { return fn.apply(this, arguments); };
    case 7 : return function (a,b,c,d,e,f,g) { return fn.apply(this, arguments); };
    case 8 : return function (a,b,c,d,e,f,g,h) { return fn.apply(this, arguments); };
    case 9 : return function (a,b,c,d,e,f,g,h,i) { return fn.apply(this, arguments); };
    default : return function (a,b,c,d,e,f,g,h,i,j) { return fn.apply(this, arguments); };
    }
};
用法示例:

var realFn = function () {
    return "blah";
};

lengthSix = makeFunc(6, realFn);

lengthSix.length; // 6
lengthSix(); // "blah"
就我个人而言,每当我在编程时使用复制和粘贴时,我总是会畏缩,所以我很高兴听到任何更好的选择

更新

我想到了一种可以适用于任意大小的方法,与上面的示例不同,上面的示例受复制和粘贴次数的限制。本质上,它会动态创建一个函数(使用
new function
),该函数将返回一个大小合适的函数,然后该函数将代理传递给它的任何函数。是的,那确实伤了你的头。不管怎样,我想我应该对照上面的标准来衡量它

(你也可以在那里看到“邪恶”代码)

邪恶的方法比黑客的复制面食方法慢几百倍,所以就这样吧

根据第103页的说明,
函数
对象上的
.length
参数不可写,因此在函数声明且不可更改时设置该参数(如果按照规范实现)

因此,根据需要创建具有特定
.length
的函数的唯一方法是让一堆不同长度的函数(正如nickf所建议的那样)、创建一个函数对象(正如您已经提到的)或者使用动态创建的字符串来使用
eval()
。我不知道你到底想解决什么问题,但我个人认为使用eval()没有错,如果你知道使用eval()的代码的源代码,并且有办法检查它,或者知道它会有什么或不会有什么。在本例中,在对字符串调用eval()之前,以编程方式在字符串中生成一定数量的参数不会带来任何安全风险


如果这都是您自己的代码,您可以在函数
.dynLength
上创建一个新属性,该属性是可变的,并将其设置为您想要的任何属性,然后让您的代码使用该属性。

我正在做一些类似于您所要求的事情,使用大致如下:

/* Make a new function with a given size */
function SizedFunc(num_args) {
  if(SizedFunc.sizedFuncs === undefined) SizedFunc.sizedFuncs = {};
  if(SizedFunc.sizedFuncs[num_args] === undefined) {
    var argNames = [];
    for(var i = 0; i < num_args; ++i) {
      argNames.push('arg' + i);
    }
    SizedFunc.sizedFuncs[num_args] = new Function(argNames, 'return this.apply(null, arguments);');
  }
  return SizedFunc.sizedFuncs[num_args];
}
我相信这也有很多不好的原因(首先是使用以这种方式创建的绑定意义函数不能绑定到对象),但在需要能够动态创建任意长度的函数的情况下,它非常有用。

有一个npm模块,它可以满足您的需要:

const arity = require('util-arity');

arity(3, () => {}).length;  //» 3

函数的
length
属性为,这意味着您可以使用来更改函数的length值。例如:

function hi() {}
hi.length === 0; // Expected

Object.defineProperty(hi, "length", { value: 5 })
hi.length === 5; // Intriguing

这在最新版本的Chrome和Firefox中有效,但在Safari(v9.1.1)中不起作用。

有趣的是,是什么原因让您考虑这个问题?为什么要设置长度?您知道,当您实际调用一个函数时,您可以传递少于“预期”的参数,或者更多?(如果您传递更多,函数可以通过其
参数
对象访问它们。)出于兴趣,为什么要这样做?我正在编写一个模拟框架,我想确保对被监视的函数进行尽可能少的修改,另一个原因是为变量函数编写组合符。例如,制作一个
reversed(f)
combinator可以很容易地制作一个以相反顺序接收参数的函数,但是让返回的函数具有与原始函数相同的长度并不是一件小事。谢谢你,然而,使用
函数
eval
的真正问题是执行的范围。这并不等同于在当前范围内编写代码,这在我的情况下不起作用。@nickf-您试图解决的真正问题是什么?为什么动态地需要创建一个具有特定
.length
值的函数?它是一个库,用于包装任意函数,以执行诸如存根和间谍(例如:计算调用数、存储参数等)之类的操作。由于使用它的代码可能会检查函数的length属性,我希望确保它在包装后保持不变。这是我们需要JavaScript中的宏的原因之一。这在现代V8中也适用(我使用Node 6.x进行了测试)。谢谢也适用于节点v8.15.0!谢谢
function hi() {}
hi.length === 0; // Expected

Object.defineProperty(hi, "length", { value: 5 })
hi.length === 5; // Intriguing