簡體   English   中英

具有可變參數的新函數()

[英]new Function() with variable parameters

我需要使用new Function()構造函數創建一個參數數量可變的 function。 是這樣的:

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

myFunc = new Function(args, body);

沒有eval()可以做到嗎?


非常感謝你們,伙計們,實際上。 a+b 不是我最關心的。 我正在編寫一個可以處理和擴展模板的代碼,我需要將未知(和變量)數 arguments 傳遞到 function 中,以便將它們作為局部變量引入。

例如,如果模板包含:

<span> =a </span> 

我需要 output 參數a的值。 也就是說,如果用戶聲明將 function 擴展為

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

然后打電話

expand(4, 2, 1) 

我需要用4代替=a 是的,我很清楚 Function 類似於eval()並且運行速度非常慢,但我別無選擇。

您可以使用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構造函數更有效,並且可能是實現您需要的更合適的方法。

如果構造函數不關心您是否使用new關鍵字,@AndyE 的答案是正確的。 有些功能並不那么寬容。

如果您發現自己需要使用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"

你可以這樣做:

 let args = '...args' let body = 'let [a, b] = args;return a + b' myFunc = new Function(args, body); console.log(myFunc(1, 2)) //3

如果你只是想要一個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;

如果你想要更多,你能提供更多的細節嗎? 如果您不知道自己要做什么,那么很難說如何做某事。

你可以用幾種不同的方式來寫。

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

也許你想要一個煩人的function來呼叫一個任意的function。

// user string function
var userFunction = 'function x(...args) { return args.length}';

包起來

var annoyFn = Function('return function x(...args) { return args.length}')()
// now call it
annoyFn(args)
function construct(){
         this.subFunction=function(a,b){
         ...  
         }
}
var globalVar=new construct();   

對比

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

如果有子功能,我更喜歡第二個版本。

new Function(...)

以這種方式聲明函數會導致函數不被編譯,並且可能比其他聲明函數的方式慢。

讓我們用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>

我上面所做的是創建一個執行相同操作的function expressionfunction constructor 結果如下:

FireFox 性能結果

FireFox 性能結果

IE 性能結果

IE 性能結果

基於事實,我建議使用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));

當 b 繼承原型時, b.apply(null, arguments) 無法正常工作,因為省略了 'new',不會調用基本構造函數。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM