用純Javascript打造類似NodeJS的模組載入系統

來源:互聯網
上載者:User

NodeJS的模組系統有兩個重要的特點:

1. 模組中直接用var定義的變數是僅作用與當前模組的,而不是全域。

2. 每個模組中都可以使用require和module這兩個“全域變數”。之所以打上引號,因為它們其實是每個模組都有的通用執行個體,不同模組中的執行個體是不一樣的。

也許你會認為這兩個特性和我們在瀏覽器中使用的Javascript性質有很多不同,一定是NodeJS運行環境提供的native特性,那就不一定了。儘管沒有研究過NodeJS是如何?的,但是我們用純Javascript完全可以做出一樣的模組系統。這其實只要要用到一個Javascript中很少用的文法:new Function()。

Javascript中除了用function func(){}來定義一個函數之外,還可以用new Function()來建立一個函數。Function是Javascript中所有函數的prototype,即所有函數的基類。通過給Function.prototype增加屬性可以給所有的函數執行個體增加屬性,這也是大家相對常用的一個做法。今天要給大家介紹的是通過直接new Function()來建立一個函數,儘管這被認為效能不好,但在某些特殊情境能做到一些很有用的功能。

new Function()的詳細文法格式是:

new Function(args, body)

這裡的args是一個字串,表示函數的參數,參數之間用逗號隔開,而body則是函數體本身。比如:
var add = new Function('x, y', 'return x + y;');
這樣建立的函數就等價於:

var add = function(x, y){     return x + y;}

這兩者效果沒有任何區別,通常我們也只會用第二種做法,因為有更好的可讀性。

現在我們來看new Function的兩種潛在應用情境:
1. 避免命名衝突
大家知道通過<script>標籤引入的Javascript檔案是全域的,每個檔案中定義的變數都是全域的,這時為了避免命名衝突,可以通過如下的小技巧:

(function(){     var x = 0;     //my code})();

通過外包一個函數並立刻調用,可以做成一個閉包,其中的變數的範圍就只局限於函數體之內。從而避免了與其它的檔案之間的命名衝突。但是在有些情況下,我們需要使用一個第三方的Javascript檔案或者因為某些原因而無法修改的檔案,它完成某個獨立的任務,但是其中定義了一些全域變數。這些檔案無法被修改成使用上面提到的方法來避免命名衝突。這時我們的new Function()就可以發揮作用了。這時我們不是通過<script>引入Javascript檔案,而是通過XMLHttpRequest獲得Javascript檔案的內容,然後用如下的方式來執行這個Javascript:

var result = (new Function('', jsCode + '; return {x: x}'))();

這樣,我們相當於也是在jsCode外麵包裝了一層function,並且,我們把需要用的的結果作為傳回值返回出來,供外面程式使用。當然,對於大部分獨立的檔案,我們並不一定需要傳回值,而只是需要執行一下即可。下面來看下一個應用情境。

2. 打造自己的模組載入系統
這也是上一種應用情境的一個延伸,既然我們通過這種方式來載入Javascript檔案,何不將其做成一個通用的模組載入系統,供自己的項目使用。從而不用每個檔案都外包一層function來避免命名衝突。其實如果大家用過NodeJS,就也許知道,NodeJS中的每個模組中定義的變數都是局限於當前模組的,不會被其它模組直接使用。而且每個模組中還有一個預設的require和module變數,這兩個每個模組中都可以像使用全域變數一樣使用,但它們卻又不是全域變數,NodeJS文檔中寫的也很清楚,它們在各個模組中都是不同的執行個體。這樣,一個模組都它們進行的修改並不會影響到其它模組。你也許會認為這一定是NodeJS的native環境提供的特殊功能,但實際上,我們完全可以用純Javascript打造出一個同樣的模組機制,只需對上面提到的例子做一點修改,比如這個loader是有類似如下的代碼:

var require = getRequireInstance();var module = getModuleInstance(); //通過XMLHttpRequest獲得要載入的Javascript檔案的代碼var moduleText = getModuleText(); //執行模組代碼,並“注入”require和module變數。(new Function('require, module', moduleText))(require, module);

怎麼樣,是不是很簡單?new Function()雖然是一個很少用的功能,但是確實非常靈活,更多應用情境就靠大家繼續挖掘了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.