是否可以在新的Function()之后改变功能范围?

时间:2015-05-05 12:29:37

标签: javascript function scope

所以我有这段代码:

function fn(a){
  var f=(new Function("return a"));
  return f();
}
fn(7)//ReferenceError: a is not defined

局部变量的相同问题:

function fn(){
  var a=7;
  var f=new Function("return a");
  return f();
}
fn(7)//ReferenceError: a is not defined

我希望它返回一个但是新功能看不到, 它只能看到全局

var a=1;
function fn(a){
  var f=(new Function("return a"));
  return f();
}
fn(7)//1

通过正常初始化,函数可以看到参数。

function fn(a){
  var f=function(){return a};
  return f();
}
fn(7)//7

我需要在项目中调用基本构造函数,并且不能使用全局变量。 我知道我可以通过给新创建的函数提供参数来解决这个问题并用它来调用它:

function fn(a){
  var f=(new Function('a',"return a"));
  return f(a);
}
fn(7)//7

还可以使用一些解析函数和一些愚蠢的长方法来使传入的参数可以这样到达:

function parsargs(funct){
   //some parsing methodes giving back argument name list from funct.toString()
  return "['a','b']";//like this
}


function fn(a,b){
  var arrgstr,retfunc;

  arrgstr="";
  for(var i in arguments)
  {
    if(i<arguments.length-1)
      arrgstr+=arguments[i]+",";
    else
      arrgstr+=arguments[i];
  }
  //return arrgstr;
  retfunc="var f=new Function("+parsargs()+",'return b*a');return f("+arrgstr+")";
  return (new Function(retfunc))();
}
fn(7,4)//28

但是必须有一种更简单的方法来达到局部变量和函数...... 有什么建议吗?

PS:  我正在尝试替换项目中的eval()

以下是我原始问题的简化版本: fiddle

答案是否 ......

4 个答案:

答案 0 :(得分:2)

您的确切问题不明确,但假设您可以使用arguments.callee(即非严格模式)并且您希望能够在fn中拥有任何参数名称,那么“可能”这样做:

function fn(a,b){
  var strargs = arguments.callee.toString().match(/\(([^\)]*)\)/)[1];
  return (new Function(strargs.split(","),"return a+b")).apply(null,arguments);
}
console.log(fn(7, 3)) // 10

但我强烈认为这是一个XY问题,我们可以在知道要解决的真正原始问题时给出更有用的答案。

答案 1 :(得分:1)

为什么这不像你想的那样简单,因为JavaScript不会盲目地将变量放在一个范围内。相反,它解析函数体(尽可能好)并确定代码需要哪些变量。然后,它将查找外部作用域中的变量,为它们创建引用并将这些引用附加到新函数。这就是在最终执行函数时,可以在函数内部访问外部作用域的变量。

您想要从字符串主体构建函数。 JavaScript无法判断正文将使用哪些变量,因此,它不会使这些变量可用。

要使其适用于函数参数,请使用apply():

function fn(a){
   var argref = arguments; // create reference to the arguments of fn() and hence to a or any other arguments
   var func = new Function("return arguments[0]");
   var wrapper = function() {
      return func.apply(null, argref);
   };
   return wrapper;
}

请注意,您仍然无法按名称引用参数,因为代码永远不会指定func的参数名称是什么 - JavaScript无法神奇地读取您的想法并执行您想要的操作。如果要按名称访问参数,则需要告诉解释器名称。

这个问题有一些代码如何从函数引用中确定名称:How to get function parameter names/values dynamically from javascript

我没有看到一种方法来使局部变量可用而不将它们作为参数传递给fn()。即使您在fn()内使用它们,它们也会在最终执行func()时超出范围。

一个简单的解决方案是将对象传递给fn()

function fn(conf) {
   var func = new Function('conf', "return conf.a");
   var wrapper = function(conf) {
       return func.apply(null, conf);
   };
   return wrapper;
}

fn({a:7});

答案 2 :(得分:1)

new Function doesn't create a closure context,但是eval

这是一种使用任意评估主体构建函数并访问调用范围的低技术方法:

function f(a) {
  return eval("(function() { return a })")()
}

f(10) // 10

答案 3 :(得分:1)

您可以使用引用所需局部变量的上下文call新函数:

function f(a) {
  var b = 30;
  return new Function("return this.a + this.b").call({ a: a, b: b })
}

f(10) // 40