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

nic*_*ckf 11 javascript

length函数属性告诉'expected'参数列表有多长:

console.log((function () {}).length);  /* 0 */
console.log((function (a) {}).length); /* 1 */
console.log((function (a, b) {}).length); /* 2 etc. */
Run Code Online (Sandbox Code Playgroud)

但是,它是一个只读方法:

f = function (a) {};
alert(f.length); // 1
f.length = 3;
alert(f.length); // 1
Run Code Online (Sandbox Code Playgroud)

有没有办法以编程方式设置该长度?到目前为止我最接近的是使用Function构造函数:

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

但是,使用Function基本上是相同的eval,我们都知道它有多糟糕.我还有其他选择吗?

Xav*_*avi 8

事实证明length函数的属性是可配置的,这意味着您可以使用.defineProperty更改函数的长度值.例:

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

Object.defineProperty(hi, "length", { value: 5 })
hi.length === 5; // Intriguing
Run Code Online (Sandbox Code Playgroud)

这适用于最新版本的Chrome和Firefox,但它在Safari(v9.1.1)中不起作用.


nic*_*ckf 6

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

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); };
    }
};
Run Code Online (Sandbox Code Playgroud)

用法示例:

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

lengthSix = makeFunc(6, realFn);

lengthSix.length; // 6
lengthSix(); // "blah"
Run Code Online (Sandbox Code Playgroud)

就个人而言,每当我在编程时使用复制和粘贴时,我总是畏缩,所以我很高兴听到任何更好的选择.

更新

我想到了一种可以适用于任意大小的方法,与上面的例子不同,后者受到你想要复制和粘贴多少次的限制.本质上,它动态创建一个函数(使用new Function),它将返回一个正确大小的函数,然后只是代理通过你传递给它的任何函数.是的,这确实伤到了你的头脑.无论如何,我以为我会根据上述情况对它进行基准测试......

http://jsperf.com/functions-with-custom-length(你也可以看到'邪恶'代码).

邪恶的方法比hacky copypasta方法慢几百倍,所以你去.