eval可以访问外部函数吗?

时间:2014-12-11 19:49:46

标签: javascript jquery eval

我公司允许我们在线编写javascript编辑器中的代码。其他库已预先加载,因此我们编写的代码可以访问这些库。

具体来说,我们可以在代码中使用Underscore.js和jQuery.js函数。我们也可以使用我们自己的库Graphie.js。

为了节省时间,我慢慢建立了自己的个人功能集,我将其复制并粘贴到我编写的每个代码中。这组函数现在已经很长了,我想从外部获取它(为了节省空间等)。

$.getScript( 'url/to/myfunctions.js' )

我尝试了上面的代码,但实在太好了。这个jQuery函数getScript似乎将myfunctions作为自己的独立单元运行。这失败了,因为myfunctions使用我们的Graphie.js函数。

$.get( 'url/to/myfunctions', eval )

以上代码提取并成功eval我的代码(我配置了我的服务器)。也太好了,不可能。我的代码中的任何jQuery和Underscode函数实际上都有效。但是我的代码中的任何Graphie函数都会导致错误。

4 个答案:

答案 0 :(得分:3)

而不是

$.get( 'url/to/myfunctions', eval );

$.get( 'url/to/myfunctions', function(code) { eval(code); } );

这样,eval函数将在与其余代码相同的范围内执行,而不是在jQuery的范围内。获取并执行代码后,您可以继续执行其余代码:

$.get( 'url/to/myfunctions', function(code) {
  eval(code);
  callback();
});

function callback() {
  // Your code goes here
}

解释

出于解释的目的,让我们使用这个简化的环境模型,在其中执行代码:

// JQuery is defined in the global scope
var $ = {
  get: function( url, fn ) {
    var responses = {
      "url/to/myfunctions": "try {\
        if(graphie) log('Graphie is visible.');\
      } catch (e) {\
        log('Graphie is not visible. (' + e + ')');\
      }"
    }; fn( responses[url] );
  }
};

(function() {
  // Graphie is defined in a local scope
  var graphie = {};
  (function() {
    // Your code goes here
    $.get( "url/to/myfunctions", eval );
    $.get( "url/to/myfunctions", function(code) { eval (code); } );
  })();
})();
The output: <ol id="output"></ol>
<script>
  function log(msg) {
    var el = document.createElement("li");
    el.appendChild(document.createTextNode(msg));
    output.appendChild(el);
  }
</script>

如您所见,传递给$.get的函数在其正文中执行。如果您只将eval传递给$.get,那么您不会捕获局部变量graphie,这对于已评估的代码是不可见的。通过将eval包装在匿名函数中,可以捕获对局部变量graphie的引用,然后对已计算的代码可见。

答案 1 :(得分:0)

我建议不要使用eval。但是,您可以遵循以下模型。

首先在myFunctions.js中,将所有代码包装到一个函数中。

(function(_, $, graphie) {
   // declare all your functions here which makes use of the paramters
}) // we will be calling this anonymous function later with parameters

然后在获得脚本之后你就可以了

$.get( 'url/to/myfunctions', function(fn){
    var el = document.createElement('script');
    el.type = 'text/javascript';
    el.text = fn + '(_, jQuery, Graphie);';
    document.head.appendChild(el);
});

请注意,我已将Graphie作为参数,但我不确定。所以在那里放置正确的graphie变量。

答案 2 :(得分:0)

假设您对此脚本具有ajax访问权限(因为这是$ .get在您显示的示例代码中所做的事情),您可以尝试使用jQuery&#39; .html()来放置脚本使用页面的可变环境执行它。

$.ajax({
        url: 'url/to/myfunctions.js',
        type: 'GET',
        success: function (result) {
            var script = '<scr'+'ipt>'+result+'</scr'+'ipt>';
            var div = $("<div>");
            $("body").append(div);
            div.html(script);
        }
});

在内部,此脚本最终将由jQuery的globalEval函数执行。 https://github.com/jquery/jquery/blob/1.9.1/src/core.js#L577

// Evaluates a script in a global context
// Workarounds based on findings by Jim Driscoll
// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
globalEval: function( data ) {
    if ( data && jQuery.trim( data ) ) {
        // We use execScript on Internet Explorer
        // We use an anonymous function so that context is window
        // rather than jQuery in Firefox
        ( window.execScript || function( data ) {
            window[ "eval" ].call( window, data );
        } )( data );
    }
}

我还在这里问了一个与此相关的问题:Why is it that script will run from using jquery's html but not from using innerHTML?

答案 3 :(得分:0)

感谢大家的帮助,以下是有效的解决方案......

myfunctions.js文件必须包含在函数中:

function everything(_,$,Graphie){
    // every one of myfunctions now must be attached to the Graphie object like this:
    Graphie.oneOfMyFunctions = function(input1,input2,etc){
        // content of oneOfMyFunctions
    }
    // the rest of myfunctions, etc.
}

然后在我的代码中我可以使用:

检索它
$.get( '//path/to/myfunctions', eval )
everything(_,jQuery,mygraphievar);

不知何故,eval编码的代码无法访问全局变量mygraphievar,这就是为什么它必须传入而不是eval的一部分ed代码(这里Amit犯了一个小错误)。

此外,everything函数在$.get()的外部执行,以便在执行以下任何其他代码之前对mygraphievar进行更改。

应该注意$.get()实际上是一个异步函数,在执行其他代码之前不会调用eval。这导致代码在我第一次运行时失败,但在第一次将函数保存在内存中然后一切正常。正确的解决方案是在$.get()的回调函数中编写我想要执行的所有代码,但我很懒。

还应该知道$.getScript()可以使用稍微简单的解决方案,但我没有时间对其进行验证。