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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 11:17:03  来源:igfitidea点击:

new Function() with variable parameters

javascript

提问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 =awith 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.

我需要=a4. 是的,我很清楚 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 newoperator, Functiongives 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 newkeyword or not. Some functions are not as forgiving.

如果构造函数不关心您是否使用new关键字,@AndyE 的答案是正确的。有些功能并不那么宽容。

If you find yourself in a scenario where you needto use the newkeyword 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 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 expressionand function constructorperforming same operation. The result is as follows:

我上面所做的是创建一个function expressionfunction constructor执行相同的操作。结果如下:

FireFox Performance Result

FireFox 性能结果

FireFox Performance Result

FireFox 性能结果

IE Performance Result

IE 性能结果

IE Performance Result

IE 性能结果

Based on facts I recommend to use function expressioninstead 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});