带有可变参数的新Function()

时间:2010-11-15 10:51:41

标签: javascript

我需要使用new Function()构造函数创建一个具有可变数量参数的函数。像这样:

args = ['a', 'b'];
body = 'return(a + b);';

myFunc = new Function(args, body);

是否可以在没有eval()的情况下执行此操作?


非常感谢,伙计们!实际上,a + b不是我主要关注的问题。我正在研究一个处理和扩展模板的代码,我需要将未知(和变量)数量的参数传递给函数,以便将它们作为局部变量引入。

例如,如果模板包含:

<span> =a </span> 

我需要输出参数a的值。也就是说,如果用户声明扩展功能为

var expand = tplCompile('template', a, b, c) 

然后调用

expand(4, 2, 1) 

我需要用=a替换4。是的,我很清楚,功能类似于eval()并且运行速度非常慢,但我没有其他选择。

10 个答案:

答案 0 :(得分:45)

您可以使用apply()执行此操作:

args = ['a', 'b', 'return(a + b);'];
myFunc = Function.apply(null, args);

如果没有new运算符,Function会得到完全相同的结果。您可以使用push()unshift()splice()等数组函数修改数组,然后再将其传递给应用。

您也可以将逗号分隔的参数字符串传递给 Function

args = 'a, b';
body = 'return(a + b);';

myFunc = new Function(args, body);

在旁注中,您是否知道arguments对象?它允许您使用数组样式括号表示法获取传递给函数的所有参数:

myFunc = function () {
    var total = 0;

    for (var i=0; i < arguments.length; i++)
        total += arguments[i];

    return total;
}

myFunc(a, b);

这比使用 Function 构造函数更有效,并且可能是实现所需内容的更合适的方法。

答案 1 :(得分:7)

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

如果您发现自己处于需要使用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及更高版本!

// 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"

答案 2 :(得分:2)

您可以这样做:

let args = '...args'
let body = 'let [a, b] = args;return a + b'

myFunc = new Function(args, body);
console.log(myFunc(1, 2)) //3

答案 3 :(得分:0)

如果您只是想要一个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;
}

然后,

sum() === 0;
sum(1) === 1;
sum([1, 2]) === 3;
sum(1, 2, 3) === 6;
sum([-17, 93, 2, -841]) === -763;

如果您想要更多,请提供更多详细信息?如果你不知道自己要做什么,就很难说你怎么做。

答案 4 :(得分:0)

有几种不同的方法可以写出来。

// 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);

答案 5 :(得分:0)

答案 6 :(得分:-1)

new Function(...)
  

以这种方式声明功能会导致   该函数不被编译,和   可能比另一个慢   宣布职能的方式。

让我们用JSLitmus 检查它并运行一个小的测试脚本:

<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>

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

FireFox效果结果

FireFox Performance Result

IE效果

IE Performance Result

根据事实,我建议使用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));

答案 7 :(得分:-1)

function construct(){
         this.subFunction=function(a,b){
         ...  
         }
}
var globalVar=new construct();   

VS

var globalVar=new function (){
              this.subFunction=function(a,b){
              ...
              }
}

如果有子功能,我更喜欢第二个版本。

答案 8 :(得分:-1)

当b继承原型时,b.apply(null,arguments)无法正常工作,因为省略了'new',不会调用基础构造函数。

答案 9 :(得分:-1)

在此示例中,我使用了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});