如何在闭包

时间:2017-07-15 13:44:08

标签: javascript closures eval v8 ecmascript-7

考虑这段代码

'use strict';

var factory = () => script => eval(script);
var closure = factory();

closure('var v = 0');
var val = closure('typeof v');

console.log(val);

这是我尝试实现它。我想创建一个闭包,然后允许用户在该闭包中创建一个新的局部变量。这甚至可能吗?

我在某处读到“native function'eval'甚至可以在本地执行上下文中创建一个新变量。”。那么,为什么它不适用于我的例子呢?我的猜测是因为函数完成执行并且函数结束后的变量数量无法更改,但我不确定。

我的示例脚本创建了一个闭包,并尝试在该闭包中声明并初始化新变量v,并为其分配编号0。我希望typeof v的结果应为number,但实际上undefined

所以,我有两个问题:

  1. 为什么不按预期创建变量v
  2. 如何实际实现(工作示例是什么)?

3 个答案:

答案 0 :(得分:2)

嗯,它是本地范围的,但有点太本地

var factory = () =>{
  return script =>{
   //this is the scope. you cant access any variables outside of this.
   eval(script);
  };
  //you want to eval here, which is impossible
};

你可以做很多hacky范围的事情来解决这个问题(在上下文中存储所有变量):

var factory = (context={}) => script =>{ with(context){ return eval(script); }};

您需要在创建时初始化所有局部变量:

var exec=factory({v:0, b:undefined});// note that you need to set a value explicitly {v,b} wont worm

然后按预期工作:

console.log(
 exec("v"),//0
 exec("v=2"),//2
 exec("v"),//2
 typeof v //undefined
);

http://jsbin.com/xibozurizi/edit?console

如果你不想那么深入,你唯一可以做的就是连接字符串:

var factory =  code => concat => (eval(code),res=eval(concat),code+=concat,res);
// or shorter / more buggy 
var factory =  code => concat => eval(code+=";"+concat);

var exec=factory("var a=1;");
console.log(
 exec("a;"),//1
 exec("var b=a+1"),
 exec("b"),//2
 tyepof a, typeof b //undefined
);

http://jsbin.com/midawahobi/edit?console

上面的代码将多次运行字符串,这可能不需要。另一种方法:

var factory=code=>({
  code,
  run(c){
    return eval(this.code+";"+c);
  },
  add(c){ this.code+=";"+c}
});

所以你可以做到

var exec=factory("var a='hello'");
exec.run("alert(a)")//alerts hello
exec.add("var b=a+' world'");
console.log(exec.code,exec.run("b"));//hello world, the upper alert isnt run again

http://jsbin.com/lihezuwaxo/edit?console

请注意,评估总是一个坏主意......

答案 1 :(得分:0)

您对[ {"idType":"ID_ISIN","idValue":"US4592001014"}, {"idType":"ID_WERTPAPIER","idValue":"851399","exchCode":"US"}, {"idType":"ID_BB_UNIQUE","idValue":"EQ0010080100001000","currency": "USD"}, {"idType":"ID_SEDOL","idValue":"2005973","micCode":"EDGX", "currency":"USD"} ] 的调用会创建一个新变量,并且会在调用的本地执行上下文中执行此操作。该上下文是内部该函数,因此它不会影响之外的上下文,您调用eval()

一般来说,closure()一般要严格避免。它使得优化变得困难(或不可能),因此优化器将忽略使用它的函数。在某些罕见的情况下它很有用,但声明一个新的局部变量并不像其中之一。

答案 2 :(得分:0)

你可以这样做

var factory = () => script => eval(script);
var closure = factory();
var v;
closure('v=20')