貌似WEB開發初期,相關腳本語言都是沒有考慮到模塊化和命名空間的,好比javascript、asp、php等,隨着WEB開發規模愈來愈大,編程語言體系愈來愈成熟,模塊化和命名空間成爲必須的語言特性。遺憾的是,javascript目前尚未從語言層面對模塊化和命名空間進行支持,但基於語言的靈活性,能夠變通的實現。
注:commonJS規範提出了模塊化和命名空間規範,NodeJS實現了此規範。javascript
什麼是模塊?php
通常來說,模塊是一個獨立的JS文件。模塊文件能夠包含一個類定義、一組相關類、一個實用函數庫或者一些待執行的代碼。模塊化的目標是支持大規模的程序開發,處理分散源中代碼的組裝,而且能讓代碼正確運行,哪怕包含了不須要的模塊代碼,也能夠正確執行代碼。java
理想狀態下,全部模塊都不該當定義超過一個全局標識。經過把模塊定義在某個函數的內部來實現,定義的變量和函數都屬於該函數的局部變量,在函數外不可見。實際上,能夠將這個函數做用域用作模塊的命名空間(模塊函數)。而函數都是做爲全局對象的一個屬性,而javascript代碼模塊化,所必須遵照的最重要的規則就是:避免定義全局變量。由於,當定義一個全局變量時,都有被其它模塊覆蓋的危險。python
那麼該如何作呢?程序員
var ModuleClass = {}; ModuleClass.函數名1=function(){ 函數體;//這個函數看起來是一個對象的方法。對,能夠利用對象做爲一個名字空間 } ModuleClass.函數名2=function(){ 函數體; }
ModuleClass是一個對象,使用對象做爲一個名字空間,將全部的函數及變量都放在其中。即便函數或變量重名( 即不一樣對象中有相同函數名),它們不在一個名字空間中,這樣就不會有被覆蓋的危險了。 ModuleClass其實就是在全局變量中定義了一個標示符,爲了不重名,咱們應該保證對象名稱的惟一性。編程
命名空間編程語言
單獨一個對象名稱惟一性保證是很是困難的,在javasript中能夠有兩個辦法來避免這種衝突。ide
目錄方式:將同名對象放到不一樣目錄,好比放到util目錄中「util/ModuleClass」,代碼應該這樣寫:模塊化
var util; if(!util) util = {};//第一級域名 util.ModuleClass = {};//第二級域名 util.ModuleClass.函數名1=function(){ 函數體; } util.ModuleClass.函數名2=function(){ 函數體; }
這是一級目錄的形式,若是是多級目錄呢,就編程了JAVA包命名方式了。函數
類JAVA包名方式:com.公司名.項目名.util.ModuleCalss,相應的目錄路徑是:com/公司目錄/項目目錄/util/ModuelClass.js
var com; if(!com) com={};//若是com不存在,則新生成一個 else if(typeof com!="object"){//若是已存在,但不是一個對象,則拋出一個異常 throw new Error("com already exists and is not an object"); } if(!com.util) com.util={};//若是com.util不存在則新生成一個 else if(typeof com.util!="object"){//若是com存在,但不是一個對象,則拋出一個異常 throw new Error("com.util already exists and is not an object"); } if(!com.util.ModuleClass){//若是com.util.ModuleClass存在,則直接拋出異常 throw new Error("com.util.ModuleClass already exists"); } com.util.ModuleClass = {//在com.util.ModuleClass不存在的狀況下,咱們才能正常使用在此命名空間下定義的代碼 函數1:function(){ 函數體; }, 函數2:function(){ 函數體; } };
JAVA中包命名和目錄路徑的對應關係自己就很是不靈活,JVM類加載機制依賴目錄路徑來查找類,並加載。在動態語言中,應該像python同樣,只需將模塊文件放到一個目錄,而後在類中引入便可,帶來相對路徑名稱。改變目錄,只須要修改類的引入申明代碼,而不須要修改模塊文件。
從語言角度,這很是的不合理且弱智,期待全部EMCAcript實現都實現CommonJS規範。
犀牛書提供了一個工具類,幫助程序員來建立命名空間。
代碼/* == Module and NameSpace tool-func == * author : hongru.chen * date : 2010-12-05 */ var Module; //check Module --> make sure 'Module' is not existed if (!!Module && (typeof Module != 'object' || Module.NAME)) throw new Error("NameSpace 'Module' already Exists!"); Module = {}; Module.NAME = 'Module'; Module.VERSION = 0.1; Module.EXPORT = ['require', 'importSymbols']; Module.EXPORT_OK = ['createNamespace', 'isDefined', 'modules', 'globalNamespace']; Module.globalNamespace = this; Module.modules = {'Module': Module}; // create namespace --> return a top namespace Module.createNamespace = function (name, version) { if (!name) throw new Error('name required'); if (name.charAt(0) == '.' || name.charAt(name.length-1) == '.' || name.indexOf('..') != -1) throw new Error('illegal name'); var parts = name.split('.'); var container = Module.globalNamespace; for (var i=0; i<parts.length; i++) { var part = parts[i]; if (!container[part]) container[part] = {}; container = container[part]; } var namespace = container; if (namespace.NAME) throw new Error('module "'+name+'" is already defined'); namespace.NAME = name; if (version) namespace.VERSION = version; Module.modules[name] = namespace; return namespace; }; // check name is defined or not Module.isDefined = function (name) { return name in Module.modules; }; // check version Module.require = function (name, version) { if (!(name in Module.modules)) throw new Error('Module '+name+' is not defined'); if (!version) return; var n = Module.modules[name]; if (!n.VERSION || n.VERSION < version) throw new Error('version '+version+' or greater is required'); }; // import module Module.importSymbols = function (from) { if (typeof form == 'string') from = Module.modules[from]; var to = Module.globalNamespace; //dafault var symbols = []; var firstsymbol = 1; if (arguments.length>1 && typeof arguments[1] == 'object' && arguments[1] != null) { to = arguments[1]; firstsymbol = 2; } for (var a=firstsymbol; a<arguments.length; a++) { symbols.push(arguments[a]); } if (symbols.length == 0) { //default export list if (from.EXPORT) { for (var i=0; i<from.EXPORT.length; i++) { var s = from.EXPORT[i]; to[s] = from[s]; } return; } else if (!from.EXPORT_OK) { // EXPORT array && EXPORT_OK array both undefined for (var s in from) { to[s] = from[s]; return; } } } if (symbols.length > 0) { var allowed; if (from.EXPORT || form.EXPORT_OK) { allowed = {}; if (from.EXPORT) { for (var i=0; i<form.EXPORT.length; i++) { allowed[from.EXPORT[i]] = true; } } if (from.EXPORT_OK) { for (var i=0; i<form.EXPORT_OK.length; i++) { allowed[form.EXPORT_OK[i]] = true; } } } } //import the symbols for (var i=0; i<symbols.length; i++) { var s = symbols[i]; if (!(s in from)) throw new Error('symbol '+s+' is not defined'); if (!!allowed && !(s in allowed)) throw new Error(s+' is not public, cannot be imported'); to[s] = form[s]; } }
使用方式
//爲模塊建立名稱空間 Module.createNamespace("com.davidflannagan.Class"); //填充名稱空間 com.davidflanagan.Class.define=function(data){}; com.davidflanagan.Class.provides=functon(o,c){}; //檢查模塊指定版本是否存在 Module.require("com.davidflanagan.Class",1.0); //使用模塊名稱標示符導入模塊 Module.importSymbols(Module); importSymbols(com.davidflanagan.Class); var Class={}; importSymbols(com.davidflanagan.Class,Clas,"define");
至此,javascript核心語法基本介紹完畢。