2011-02-14 200 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()工作作爲一個承諾的)。