2011-02-14 149 views
11

内JS文件,我只是想有一个JS文件的能力,但又不希望它在全球范围内评估。包括私人范围

我已经掠过labjs和requirejs,虽然他们可以做其他的事情1000它似乎并不认为要么是能够解决这个问题。

我知道我可以包装foo.js的代码,以便它期望某个上下文,并且可以在其中执行操作,但这不是我正在寻找的操作(不得不更改源文件)。相反,我希望源JS文件保留为不需要任何类型的元数据的任何其他JS文件,或通过代码解析运行时执行上下文,包含文件本身;在包含文件之外,没关系。

为清楚起见,一些简单的演示:

/* 
* Example 1 - apply to current context 
*/ 
function x() { 
    include('foo.js'); // provides foo() 
    foo(); // ok! 
} 
foo(); // not ok! 


/* 
* Example 2 - apply to namespace context 
*/ 
include.apply(ns, ['foo.js']); // provides foo() 
ns.foo(); // ok! 
foo(); // not ok! 

我知道,这可能可以使用eval()或通过创建具有字符串new Function可以实现,但我希望有一个更好的解决方案。

+0

Caja可能值得一看:https://code.google.com/p/google-caja/ – ide 2011-02-15 02:53:22

+2

+1有趣的问题,我说用eval去吧。是的,如果误用了,eval可能是危险的,但是如果它完成了工作并且把它放在了良好的位置...... – Zevan 2011-02-15 03:52:03

回答

1

要关闭掉这个老问题,遗憾的是没有可接受的解决方案被发现。一些很好的建议,但都打破了我的要求。我想这可能不适用于该语言的当前功能集。

3

还有就是要做到这一点,而不依赖于包括源文件遵循某种模式没有干净方式(我能想到的注入每个文件到自己的iframe的可能性,所以他们与运行他们自己window,但我不认为这是理想的)。

这并不一定意味着你不能达到包含文件的脱钩(不运行时环境的意识,你说的),但文件仍然需要是乖巧。

的CommonJS的模块系统(其RequireJS supports)示出了实现这个的一种方式。通过将代码封装在提供对象的函数中,并将所有(以前的)全局属性分配给该对象,RequireJS可以返回该对象,以便将其分配给任何范围内的任何对象。

例如:

function x() { 
    var foo = require('foo.js').foo; // provides foo() 
    foo(); // ok! 
} 
foo(); // not ok! 

var ns = require('foo.js'); 
ns.foo(); // ok! 
foo(); // not ok! 

是的,这需要编辑的源文件,但它仍然提供了你后的好处。

3

我不认为这是可能比你自己列出其他的方式来做到这一点。

一种解决方案是包装中的代码在服务器侧的功能和写入的包括加载JS文件和用功能的名称空间响应函数。我想到了一个与node.js中的require函数类似的解决方案。

在服务器端

裹代码

require.response('foo', function(exports) { 

    // Content in foo.js 
    exports.a = function() { return 'A'; } 
    this.b = function() { return 'B'; } 
    function c() { return 'c'); } 

}); 

客户端JS:

window['require'] = (function() { 

    var list = {}; 
    function require(name, cb) { 
     if (list[name]) { 
      if (list[name].ns) { 
       cb(list[name].ns); 
      } 
      else { 
       list[name].cb.push(cb); 
      } 
     } 
     else { 
      list[name] = {cb: [cb]}; 

      // Code to load js file 

     } 
    } 

    require.response = function(name, func) { 
     var ns = {}; 
     list[name].ns = ns; 
     func.call(ns); 
     for(var i = 0, l = list[name].cb; i < l; i++) { 
      list[name].cb[i](ns); 
     } 
    } 

    return require; 

}()); 

用法示例:

require('foo', function(foo) { 
    foo.a(); // ok 
    foo.b(); // ok 
    foo.c(); // error 
}; 

foo.a(); // error 
this.a(); // error 
c(); // error 
0

clientside-require package利用iframe来包含加载的javascript范围。

加载脚本到你的页面之后:

<script src = "path/to/clientside-require/src/index.js"></script> 

你可以进行你想要的功能如下:

/* 
* Example 1 - apply to current context 
*/ 
require("foo.js") 
    .then((foo)=>{ 
    foo(); // ok 
    }) 
foo(); // not ok 


/* 
* Example 2 - apply to namespace context 
*/ 
var promise_foo_attached = require("foo.js") 
    .then((foo)=>{ 
    window.ns.foo = foo; // provides foo to ns 
    }) 

// then, as long as promise_foo_attached has resolved: 
ns.foo(); // ok! 
foo(); // not ok! 

注意,因为浏览器不允许资源的同步加载(因糟糕的用户体验)任何试图用javascript加载外部脚本的尝试都必须是异步的(并因此使用承诺)。

除非浏览器启用同步加载,否则此格式将与我们正在寻找的最接近。


作为额外的奖励,所述require()功能,该脚本负载可以用来加载htmlcssjson,甚至node_modules(只要该模块能够与require()工作作为一个承诺的)。