Javascript 带有可变参数的 new Function()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4183591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
new Function() with variable parameters
提问by mtelis
I need to create a function with variable number of parameters using new Function()
constructor. Something like this:
我需要使用new Function()
构造函数创建一个具有可变数量参数的函数。像这样的东西:
args = ['a', 'b'];
body = 'return(a + b);';
myFunc = new Function(args, body);
Is it possible to do it without eval()
?
没有它可以做到eval()
吗?
Thank you very much, guys! Actually, a+b was not my primary concern. I'm working on a code which would process and expand templates and I needed to pass unknown (and variable) number of arguments into the function so that they would be introduced as local variables.
非常感谢你们!实际上,a+b 并不是我最关心的问题。我正在编写一个可以处理和扩展模板的代码,我需要将未知(和可变)数量的参数传递给函数,以便将它们作为局部变量引入。
For example, if a template contains:
例如,如果模板包含:
<span> =a </span>
I need to output the value of parameter a
. That is, if user declared expanding function as
我需要输出 parameter 的值a
。也就是说,如果用户将扩展函数声明为
var expand = tplCompile('template', a, b, c)
and then calls
然后打电话
expand(4, 2, 1)
I need to substitute =a
with 4
. And yes, I'm well aware than Function is similar to eval()
and runs very slow but I don't have any other choice.
我需要=a
用4
. 是的,我很清楚 Function 与 Function 相似eval()
并且运行速度非常慢,但我别无选择。
回答by Andy E
You can do this using apply():
您可以使用apply()执行此操作:
args = ['a', 'b', 'return(a + b);'];
myFunc = Function.apply(null, args);
Without the new
operator, Function
gives exactly the same result. You can use array functions like push(), unshift()or splice()to modify the array before passing it to apply.
没有new
运算符,Function
给出完全相同的结果。您可以使用push()、unshift()或splice()等数组函数来修改数组,然后再将其传递给应用程序。
You can also just pass a comma-separated string of arguments to Function:
您也可以将逗号分隔的参数字符串传递给Function:
args = 'a, b';
body = 'return(a + b);';
myFunc = new Function(args, body);
On a side note, are you aware of the argumentsobject? It allows you to get all the arguments passed into a function using array-style bracket notation:
附带说明一下,您是否知道arguments对象?它允许您使用数组样式的括号表示法获取传递给函数的所有参数:
myFunc = function () {
var total = 0;
for (var i=0; i < arguments.length; i++)
total += arguments[i];
return total;
}
myFunc(a, b);
This would be more efficient than using the Functionconstructor, and is probably a much more appropriate method of achieving what you need.
这比使用Function构造函数更有效,并且可能是实现您需要的更合适的方法。
回答by Thank you
@AndyE's answer is correct ifthe constructor doesn't care whether you use the new
keyword or not. Some functions are not as forgiving.
如果构造函数不关心您是否使用new
关键字,@AndyE 的答案是正确的。有些功能并不那么宽容。
If you find yourself in a scenario where you needto use the new
keyword and you need to send a variable number of arguments to the function, you can use this
如果您发现自己处于需要使用new
关键字并且需要向函数发送可变数量的参数的场景中,您可以使用这个
function Foo() {
this.numbers = [].slice.apply(arguments);
};
var args = [1,2,3,4,5]; // however many you want
var f = Object.create(Foo.prototype);
Foo.apply(f, args);
f.numbers; // [1,2,3,4,5]
f instanceof Foo; // true
f.constructor.name; // "Foo"
ES6 and beyond!
ES6 及更高版本!
// yup, that easy
function Foo (...numbers) {
this.numbers = numbers
}
// use Reflect.construct to call Foo constructor
const f =
Reflect.construct (Foo, [1, 2, 3, 4, 5])
// everything else works
console.log (f.numbers) // [1,2,3,4,5]
console.log (f instanceof Foo) // true
console.log (f.constructor.name) // "Foo"
回答by Thiago Lagden
You can do this:
你可以这样做:
let args = '...args'
let body = 'let [a, b] = args;return a + b'
myFunc = new Function(args, body);
console.log(myFunc(1, 2)) //3
回答by Chris Morgan
If you're just wanting a sum(...)
function:
如果你只是想要一个sum(...)
功能:
function sum(list) {
var total = 0, nums;
if (arguments.length === 1 && list instanceof Array) {
nums = list;
} else {
nums = arguments;
}
for (var i=0; i < nums.length; i++) {
total += nums[i];
}
return total;
}
Then,
然后,
sum() === 0;
sum(1) === 1;
sum([1, 2]) === 3;
sum(1, 2, 3) === 6;
sum([-17, 93, 2, -841]) === -763;
If you want more, could you please provide more detail? It's rather difficult to say how you can do something if you don't know what you're trying to do.
如果你想要更多,你能提供更多的细节吗?如果您不知道自己要做什么,那么很难说如何做某事。
回答by WolfRevoKcats
There's a few different ways you could write that.
你可以用几种不同的方式来写。
// assign normally
var ab = ['a','b'].join('');
alert(ab);
// assign with anonymous self-evaluating function
var cd = (function(c) {return c.join("");})(['c','d']);
alert(cd);
// assign with function declaration
function efFunc(c){return c.join("");}
var efArray = ['e','f'];
var ef = efFunc(efArray);
alert(ef);
// assign with function by name
var doFunc = function(a,b) {return window[b](a);}
var ghArray = ['g','h'];
var ghFunc = function(c){return c.join("");}
var gh = doFunc(ghArray,'ghFunc');
alert(gh);
// assign with Class and lookup table
var Function_ = function(a,b) {
this.val = '';
this.body = b.substr(0,b.indexOf('('));
this.args = b.substr(b.indexOf('(')+1,b.lastIndexOf(')')-b.indexOf('(')-1);
switch (this.body) {
case "return":
switch (this.args) {
case "a + b": this.val = a.join(''); break;
}
break;
}
}
var args = ['i', 'j'];
var body = 'return(a + b);';
var ij = new Function_(args, body);
alert(ij.val);
回答by PleaseStand
A new feature introduced in ES5 is the reduce
method of arrays. You can use it to sum numbers, and it is possible to use the feature in older browsers with some compatibility code.
ES5 中引入的一个新特性是reduce
数组的方法。您可以使用它对数字求和,并且可以在具有一些兼容性代码的旧浏览器中使用该功能。
回答by Ramiz Uddin
new Function(...)
Declaring function in this way causes the function not to be compiled, and is potentially slower than the other ways of declaring functions.
以这种方式声明函数会导致函数不被编译,并且可能比其他声明函数的方式慢。
Let is examine it with JSLitmus and run a small test script:
让我们用JSLitemus检查它并运行一个小的测试脚本:
<script src="JSLitmus.js"></script>
<script>
JSLitmus.test("new Function ... ", function() {
return new Function("for(var i=0; i<100; i++) {}");
});
JSLitmus.test("function() ...", function() {
return (function() { for(var i=0; i<100; i++) {} });
});
</script>
What I did above is create a function expression
and function constructor
performing same operation. The result is as follows:
我上面所做的是创建一个function expression
并function constructor
执行相同的操作。结果如下:
FireFox Performance Result
FireFox 性能结果
IE Performance Result
IE 性能结果
Based on facts I recommend to use function expression
instead of function constructor
基于事实,我建议使用function expression
而不是function constructor
var a = function() {
var result = 0;
for(var index=0; index < arguments.length; index++) {
result += arguments[index];
}
return result;
}
alert(a(1,3));
回答by B.F.
function construct(){
this.subFunction=function(a,b){
...
}
}
var globalVar=new construct();
vs.
对比
var globalVar=new function (){
this.subFunction=function(a,b){
...
}
}
I prefer the second version if there are sub functions.
如果有子功能,我更喜欢第二个版本。
回答by user2969819
the b.apply(null, arguments) does not work properly when b inherits a prototype, because 'new' being omitted, the base constructor is not invoked.
当 b 继承原型时, b.apply(null, arguments) 无法正常工作,因为省略了 'new',不会调用基本构造函数。
回答by Leo
In this sample i used lodash:
在这个示例中,我使用了lodash:
function _evalExp(exp, scope) {
const k = [null].concat(_.keys(scope));
k.push('return '+exp);
const args = _.map(_.keys(scope), function(a) {return scope[a];});
const func = new (Function.prototype.bind.apply(Function, k));
return func.apply(func, args);
}
_evalExp('a+b+c', {a:10, b:20, c:30});