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