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()雖然是一個很少用的功能,但是確實非常靈活,更多應用場景就靠大傢繼續挖掘瞭
摘自 Dojo中文博客-