使用eval获得适当的范围

时间:2012-10-15 07:33:52

标签: javascript eval

我正在使用这个脚本,它允许你使用插值变量构建正则表达式。目前我得到了这个并且效果很好:

function sRegExp( regex, vars ) {
  vars = Array.prototype.slice.call( arguments, 1 );
  regex = regex.toString();
  var newRegex = regex.replace(/(^\/|\/$|\/([igm]+)$)/g, '')
    .replace( /#\{(\d)\}/g, function( a, b ) { return vars[ +b ]; });
  var mods = regex.match( /\/([igm]+)$/ );
  return new RegExp( newRegex, mods ? mods[1] : '' );
}

我这样使用它:

function func() {
  var foo = 'lol';
  return sRegExp( /baz #{0}/i, foo );
}

console.log( func() ); //=> /baz lol/i

我想通过使用变量名来改进这个脚本,而不是必须使用索引并将变量作为参数传递,所以我想到使用eval,所以我摆脱了vars和稍微重构了一下代码:

function sRegExp( regex ) {
  regex = regex.toString();
  var newRegex = regex.replace(/(^\/|\/$|\/([igm]+)$)/g, '')
   .replace( /#\{(\w+)\}/g, function( a, b ) { return eval( b ); });
                 __^__                               __^__
  var mods = regex.match( /\/([igm]+)$/ );
  return new RegExp( newRegex, mods ? mods[1] : '' );
}

现在上一个例子的问题是:

console.log( func() ); //=> foo is not defined

但在全球范围内......

var foo = 'lol';
function func() {
  return sRegExp( /baz #{foo}/i );
}

console.log( func() ); //=> /baz lol/i

如何设置eval的上下文。我试过eval.call(func),但这显然不起作用。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您无法设置eval的范围。它继承了本地执行上下文,因此只能看到它的调用上下文看到的内容(在这种情况下,在func内)。不幸的是,没有办法解决这个问题。

  

当控件进入eval代码的执行上下文时,前一个活动执行上下文(称为调用上下文)用于确定作用域链,变量对象和此值。如果没有调用上下文,则初始化作用域链,变量实例化以及确定此值的操作与全局代码一样。

来自:ES 3.1 10.2.2 Eval Code

答案 1 :(得分:2)

我不是eval的粉丝,也不是混乱的全球空间。所以,我的回答是有偏见的。

您可以将命名变量作为参数传递。

function func() {
  return sRegExp( /baz #{foo}/i, { foo: "lol" } );
}

function sRegExp( regex, vars ) {
  ...
  var newRegex = regex.replace(/(^\/|\/$|\/([igm]+)$)/g, '')
      .replace( /#\{(\w+)\}/g, function( a, b ) { return vars[b]; });
  ...
}