namespace.js Javascript的命名空间库
2011-10-11 00:00
756 查看
github:https://github.com/hirokidaichi/namespace-js
定义Namespace对象:
var Namespace
现在来具体看一下Namespace对象的定义,它是一个NamespaceDefinition对象。该对象是一个函数对象(NamespaceDefinition对象的构造函数,如果不给参数的话就默认生成一个main的命名空间),还有三个属性,Object,Definition,Proc。其值依次为NamespaceObjectFactory,NamespaceDefinition,createProcedure函数对象类。
NamespaceObjectFactory:根据fqn生成NamespaceObject对象。
NamespaceObjectFactory对象只有一个create方法,参数就是命名空间的名字(Fully Qualified Name)。该方法有一个闭包环境,该环境里有一个cache变量用于缓存所有生成的NamespaceObject对象。
一个NamespaceObject对象包含有三个属性,stash(记录当前namespace),fqn(namespace名字),proc(createProcedure对象)。方法包括:enqueue,call,valueof,merge,getStash,getExport
NamespaceDefinition:
该对象包括5个属性,namespaceObject,requires,useList,stash,defineCallback。并提供了相关的方法:use,_mergeStashWithNS,loadImport,define,getStash,valueOf,apply
该对象是namespace库的核心,它提供了所有需要的方法。
初始化的时候,在NamespaceObject的proc的steps队列里追加一个函数对象,该函数将调用apply方法。
createProcedure:该对象是一个函数对象,返回Procedure对象的next方法的结果。
Procedure:
Procedure对象有三个属性:state,steps,_status(默认为init)。提供一下几种方法:next,isRunnig,enqueue,dequeue,call,_invoke。
追加定义Namespace支持的方法:
Namespace.use
Namespace.fromInternal
Namespace.GET
Namespace.fromExternal
具体看一个例子:
1:Namespace('logtest') => new NamespaceDefinition(NamespaceObjectFactory.create('logtest'))
即生成一个NamespaceDefinition对象,该对象是由NamespaceObject对象来初始化的,该对象同时还有三个属性,Object,Definition,Proc。其值依次为 NamespaceObjectFactory,NamespaceDefinition,createProcedure函数对象类。Namespace('logtest') 返回的结果就是生成的NamespaceDefinition对象,然后调用其define方法,初始化defineCallback。此时仅仅是定义,不做具体的动作。
2:使用之前定义的namespace里面的对象,Namespace.use() => Namespace().use() => Namespace('main').use()。调用use的时候初始化requires数组。
3:调用main的apply方法。看一下具体的apply方法
取出requires数组里面的对象生成Proc对象,并把该requires数组里的对象入队列steps中,还有nsDef.defineCallback也入队列(此例中为undefined),调用Proc的call方法。第一个参数是nsDef,第二个参数是回调函数。
具体使用方法:
在定义Namespace的时候,所有的定义放在define里面,并且以匿名函数的形式定义。function (ns) { // 具体的实现 // 定义对外公开的对象,外部在use该nsName之后,就可以通过ns.nsName.key()来调用它 ns.provide({ key : value});}
使用namespace.js的好处,所有的定义都是在需要的时候才开始执行的,也就是在具体使用的时候才开始解析定义。
ps:具体内部调用关系还是没有弄明白,今后有时间再整理,这篇太乱了。
定义Namespace对象:
var Namespace
现在来具体看一下Namespace对象的定义,它是一个NamespaceDefinition对象。该对象是一个函数对象(NamespaceDefinition对象的构造函数,如果不给参数的话就默认生成一个main的命名空间),还有三个属性,Object,Definition,Proc。其值依次为NamespaceObjectFactory,NamespaceDefinition,createProcedure函数对象类。
196 var createNamespace = function(fqn){ 197 return new NamespaceDefinition( 198 NamespaceObjectFactory.create(fqn || 'main') 199 ); 200 }; 201 merge(createNamespace, { 202 'Object' : NamespaceObjectFactory, 203 Definition: NamespaceDefinition, 204 Proc : createProcedure 205 });
NamespaceObjectFactory:根据fqn生成NamespaceObject对象。
NamespaceObjectFactory对象只有一个create方法,参数就是命名空间的名字(Fully Qualified Name)。该方法有一个闭包环境,该环境里有一个cache变量用于缓存所有生成的NamespaceObject对象。
一个NamespaceObject对象包含有三个属性,stash(记录当前namespace),fqn(namespace名字),proc(createProcedure对象)。方法包括:enqueue,call,valueof,merge,getStash,getExport
74 var NamespaceObject = function _Private_Class_Of_NamespaceObject(fqn){ 75 merge(this, { 76 stash: { CURRENT_NAMESPACE : fqn }, 77 fqn : fqn, 78 proc : createProcedure() 79 }); 80 }; 81 merge(NamespaceObject.prototype, { 82 enqueue: function(context) { 83 this.proc.next(context); 84 }, 85 call: function(state,callback) { 86 this.proc.call(state, callback); 87 }, 88 valueOf: function() { 89 return "#NamespaceObject<" + this.fqn + ">"; 90 }, 91 merge: function(obj) { 92 merge(this.stash,obj); 93 return this; 94 }, 95 getStash: function() { 96 return this.stash; 97 }, 98 getExport: function(importName) { 99 if (importName === '*') return this.stash; 100 101 var importNames = importName.split(/,/), 102 retStash = {}; 103 for(var i = 0,l=importNames.length;i<l;i++){ 104 retStash[ importNames[i] ] = this.stash[ importNames[i] ]; 105 } 106 return retStash; 107 } 108 }); 109 var NamespaceObjectFactory = (function() { 110 var cache = {}; 111 return { 112 create :function(fqn){ 113 _assertValidFQN(fqn); 114 return (cache[fqn] || (cache[fqn] = new NamespaceObject(fqn))); 115 } 116 }; 117 })();
NamespaceDefinition:
该对象包括5个属性,namespaceObject,requires,useList,stash,defineCallback。并提供了相关的方法:use,_mergeStashWithNS,loadImport,define,getStash,valueOf,apply
该对象是namespace库的核心,它提供了所有需要的方法。
初始化的时候,在NamespaceObject的proc的steps队列里追加一个函数对象,该函数将调用apply方法。
119 var NamespaceDefinition = function _Private_Class_Of_NamespaceDefinition(nsObj) { 120 merge(this, { 121 namespaceObject: nsObj, 122 requires : [], 123 useList : [], 124 stash : {}, 125 defineCallback : undefined 126 }); 127 var _self = this; 128 nsObj.enqueue(function($c){ _self.apply($c); }); 129 }; 130 merge(NamespaceDefinition.prototype, { 131 use: function(syntax){ 132 this.useList.push(syntax); 133 var splitted = syntax.split(/\s+/); 134 var fqn = splitted[0]; 135 var importName = splitted[1]; 136 _assertValidFQN(fqn); 137 this.requires.push(function($c){ 138 var context = this; 139 var require = NamespaceObjectFactory.create(fqn); 140 require.call(this,function(state){ 141 context.loadImport(require,importName); 142 $c(); 143 }); 144 }); 145 return this; 146 }, 147 _mergeStashWithNS: function(nsObj){ 148 var nsList = nsObj.fqn.split(/\./); 149 var current = this.getStash(); 150 151 for(var i = 0,l=nsList.length;i<l-1;i++){ 152 if( !current[nsList[i]] ) current[nsList[i]] = {}; 153 current = current[nsList[i]]; 154 } 155 156 var lastLeaf = nsList[nsList.length-1]; 157 current[lastLeaf] = merge(current[lastLeaf] || {}, nsObj.getStash()); 158 }, 159 loadImport: function(nsObj,importName){ 160 if( importName ){ 161 merge( this.stash, nsObj.getExport(importName) ); 162 }else{ 163 this._mergeStashWithNS( nsObj ); 164 } 165 }, 166 define: function(callback){ 167 var nsDef = this, nsObj = this.namespaceObject; 168 this.defineCallback = function($c) { 169 var ns = { 170 provide : function(obj){ 171 nsObj.merge(obj); 172 $c(); 173 } 174 }; 175 merge(ns, nsDef.getStash()); 176 merge(ns, nsObj.getStash()); 177 callback(ns); 178 }; 179 }, 180 getStash: function(){ 181 return this.stash; 182 }, 183 valueOf: function(){ 184 return "#NamespaceDefinition<"+this.namespaceObject+"> uses :" + this.useList.join(','); 185 }, 186 apply: function(callback){ 187 var nsDef = this; 188 createProcedure(nsDef.requires) 189 .next(nsDef.defineCallback) 190 .call(nsDef,function(){ 191 callback( nsDef.getStash() ); 192 }); 193 } 194 });
createProcedure:该对象是一个函数对象,返回Procedure对象的next方法的结果。
Procedure:
Procedure对象有三个属性:state,steps,_status(默认为init)。提供一下几种方法:next,isRunnig,enqueue,dequeue,call,_invoke。
1 var Namespace = (function(){
2 /* utility */
3 var merge = function(target, source){ // 把source的所有自身属性copy到target中去,并返回target对象 4 for(var p in source)
5 if(source.hasOwnProperty( p )) target[p] = source[p];
6 return target;
7 };
8 var _assertValidFQN = function(fqn){ // 验证namespace名字的有效性,必须是小写英数字,下划线和点
9 if(!(/^[a-z0-9_.]+/).test(fqn)) throw('invalid namespace');
10 };
11
12 var Procedure = function _Private_Class_Of_Proc(){
13 merge(this, {
14 state : {}, // 状态
15 steps : [], // 存储状态的数组
16 _status: 'init'
17 });
18 };
19 merge(Procedure.prototype, {
20 next: function(state){ // 如果state有值,存入到steps队列队尾,然后返回this
21 if(state) this.enqueue(state);
22 return this;
23 },
24 isRunning: function(){ // 判定是否为running状态
25 return (this._status === 'running');
26 },
27 enqueue: function(state){ // 这里其实是用数组steps来模拟队列,enqueue就是从队尾入队列
28 this.steps.push(state);
29 },
30 dequeue: function(){ // dequeue就是从对头出队列
31 return this.steps.shift();
32 },
33 call: function(initialState,callback){ //
34 if( this.isRunning() ) throw("do not run twice");
35
36 this.state = initialState || {}; // 保存当前state(NamespaceDefinition对象)
37 this.enqueue(function($c){ // 函数入队列steps
38 $c(); // 执行传进来的函数
39 if(callback)callback(this); // 如果存在回调函数的,执行回调函数
40 });
41 this._status = 'running'; // 设置状态为running
42 this._invoke(); // 调用_invoke
43 },
44 _invoke: function(){
45 var _self = this;
46 var step = _self.dequeue(); // 对象出队列(FIFO)
47 if( !step ){
48 _self._status = 'finished'; // 如果队列为空,则设置状态为finished
49 return;
50 } // step是数组的情况下不走这条路径
51 if( step.call ) { // 如果该对象是函数对象的时候,则执行该call方法,并指定内部this为_self.state,回调函数里面继续调用_invoke
52 return step.call( _self.state,function _cont(state){
53 if( state ) _self.state = state;
54 _self._invoke();
55 });
56 }
57 var finishedProcess = 0;
58 if( step.length === 0 ) _self._invoke(); // 如果该数组长度为0,则调用_invoke
59 for(var i =0,l=step.length;i<l;i++){ // 针对数组里的所有对象(函数对象)调用各自的call方法,并指定各自函数的this为_self.state对象(nsDef对象)
60 step[i].call(_self.state,function _joinWait(){
61 finishedProcess++;
62 if( finishedProcess == l ){
63 _self._invoke();
64 }
65 });
66 }
67 }
68 });
69
70 var createProcedure = function(state) {
71 return new Procedure().next(state);
72 };
7374 var NamespaceObject = function _Private_Class_Of_NamespaceObject(fqn){ 75 merge(this, { 76 stash: { CURRENT_NAMESPACE : fqn }, 77 fqn : fqn, 78 proc : createProcedure() 79 }); 80 }; 81 merge(NamespaceObject.prototype, { 82 enqueue: function(context) { 83 this.proc.next(context); 84 }, 85 call: function(state,callback) { 86 this.proc.call(state, callback); 87 }, 88 valueOf: function() { 89 return "#NamespaceObject<" + this.fqn + ">"; 90 }, 91 merge: function(obj) { 92 merge(this.stash,obj); 93 return this; 94 }, 95 getStash: function() { 96 return this.stash; 97 }, 98 getExport: function(importName) { 99 if (importName === '*') return this.stash; 100 101 var importNames = importName.split(/,/), 102 retStash = {}; 103 for(var i = 0,l=importNames.length;i<l;i++){ 104 retStash[ importNames[i] ] = this.stash[ importNames[i] ]; 105 } 106 return retStash; 107 } 108 }); 109 var NamespaceObjectFactory = (function() { 110 var cache = {}; 111 return { 112 create :function(fqn){ 113 _assertValidFQN(fqn); 114 return (cache[fqn] || (cache[fqn] = new NamespaceObject(fqn))); 115 } 116 }; 117 })();118
119 var NamespaceDefinition = function _Private_Class_Of_NamespaceDefinition(nsObj) {
120 merge(this, {
121 namespaceObject: nsObj,
122 requires : [],
123 useList : [],
124 stash : {},
125 defineCallback : undefined
126 });
127 var _self = this;
128 nsObj.enqueue(function($c){ _self.apply($c); });
129 };
130 merge(NamespaceDefinition.prototype, {131 use: function(syntax){ // 使用namespace 132 this.useList.push(syntax); // 该namespace字符串存入数组useList 133 var splitted = syntax.split(/\s+/); // namespace和它的对象使用空格分开 134 var fqn = splitted[0]; // 取得namespace 135 var importName = splitted[1]; // 取得namespace中的对象 136 _assertValidFQN(fqn); 137 this.requires.push(function($c){ // 放一个函数到requires数组中 138 var context = this; 139 var require = NamespaceObjectFactory.create(fqn); // 获取指定的NamespaceObject对象,之前生成过得对象可以直接从缓存中获取 140 require.call(this,function(state){ // 调用NamespaceObject对象的call方法 141 context.loadImport(require,importName); 142 $c(); 143 }); 144 }); 145 return this; 146 },147 _mergeStashWithNS: function(nsObj){
148 var nsList = nsObj.fqn.split(/\./);
149 var current = this.getStash();
150
151 for(var i = 0,l=nsList.length;i<l-1;i++){
152 if( !current[nsList[i]] ) current[nsList[i]] = {};
153 current = current[nsList[i]];
154 }
155
156 var lastLeaf = nsList[nsList.length-1];
157 current[lastLeaf] = merge(current[lastLeaf] || {}, nsObj.getStash());
158 },
159 loadImport: function(nsObj,importName){
160 if( importName ){
161 merge( this.stash, nsObj.getExport(importName) );
162 }else{
163 this._mergeStashWithNS( nsObj );
164 }
165 },166 define: function(callback){ 167 var nsDef = this, nsObj = this.namespaceObject; 168 this.defineCallback = function($c) { // 给defineCallback赋值,同时定义一下该回调函数的上下文,nsDef和nsObj两个对象。 169 var ns = { 170 provide : function(obj){ 171 nsObj.merge(obj); 172 $c(); 173 } 174 }; 175 merge(ns, nsDef.getStash()); 176 merge(ns, nsObj.getStash()); 177 callback(ns); 178 }; 179 },180 getStash: function(){
181 return this.stash;
182 },
183 valueOf: function(){
184 return "#NamespaceDefinition<"+this.namespaceObject+"> uses :" + this.useList.join(',');
185 },186 apply: function(callback){ 187 var nsDef = this; 188 createProcedure(nsDef.requires) 189 .next(nsDef.defineCallback) 190 .call(nsDef,function(){ 191 callback( nsDef.getStash() ); 192 }); 193 }194 });
195196 var createNamespace = function(fqn){ 197 return new NamespaceDefinition( 198 NamespaceObjectFactory.create(fqn || 'main') 199 ); 200 }; 201 merge(createNamespace, { 202 'Object' : NamespaceObjectFactory, 203 Definition: NamespaceDefinition, 204 Proc : createProcedure 205 });206 return createNamespace;
207 })();
追加定义Namespace支持的方法:
Namespace.use
Namespace.fromInternal
Namespace.GET
Namespace.fromExternal
1 Namespace.use = function(useSyntax){ return Namespace().use(useSyntax); } 2 Namespace.fromInternal = Namespace.GET = (function(){ 3 var get = (function(){ 4 var createRequester = function() { 5 var xhr; 6 try { xhr = new XMLHttpRequest() } catch(e) { 7 try { xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) { 8 try { xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) { 9 try { xhr = new ActiveXObject("Msxml2.XMLHTTP") } catch(e) { 10 try { xhr = new ActiveXObject("Microsoft.XMLHTTP") } catch(e) { 11 throw new Error( "This browser does not support XMLHttpRequest." ) 12 } 13 } 14 } 15 } 16 } 17 return xhr; 18 }; 19 var isSuccessStatus = function(status) { 20 return (status >= 200 && status < 300) || 21 status == 304 || 22 status == 1223 || 23 (!status && (location.protocol == "file:" || location.protocol == "chrome:") ); 24 }; 25 26 return function(url,callback){ 27 var xhr = createRequester(); 28 xhr.open('GET',url,true); 29 xhr.onreadystatechange = function(){ 30 if(xhr.readyState === 4){ 31 if( isSuccessStatus( xhr.status || 0 )){ 32 callback(true,xhr.responseText); 33 }else{ 34 callback(false); 35 } 36 } 37 }; 38 xhr.send('') 39 }; 40 })(); 41 42 return function(url,isManualProvide){ 43 return function(ns){ 44 get(url,function(isSuccess,responseText){ 45 if( isSuccess ){ 46 if( isManualProvide ) 47 return eval(responseText); 48 else 49 return ns.provide( eval( responseText ) ); 50 }else{ 51 var pub = {}; 52 pub[url] = 'loading error'; 53 ns.provide(pub); 54 } 55 }); 56 }; 57 }; 58 })(); 59 60 Namespace.fromExternal = (function(){ 61 var callbacks = {}; 62 var createScriptElement = function(url,callback){ 63 var scriptElement = document.createElement('script'); 64 65 scriptElement.loaded = false; 66 67 scriptElement.onload = function(){ 68 this.loaded = true; 69 callback(); 70 }; 71 scriptElement.onreadystatechange = function(){ 72 if( !/^(loaded|complete)$/.test( this.readyState )) return; 73 if( this.loaded ) return; 74 scriptElement.loaded = true; 75 callback(); 76 }; 77 scriptElement.src = url; 78 document.body.appendChild( scriptElement ); 79 return scriptElement.src; 80 }; 81 var domSrc = function(url){ 82 return function(ns){ 83 var src = createScriptElement(url,function(){ 84 var name = ns.CURRENT_NAMESPACE; 85 var cb = callbacks[name]; 86 delete callbacks[name]; 87 cb( ns ); 88 }); 89 } 90 }; 91 domSrc.registerCallback = function(namespace,callback) { 92 callbacks[namespace] = callback; 93 }; 94 return domSrc; 95 })(); 96 97 try{ module.exports = Namespace; }catch(e){}
具体看一个例子:
1 Namespace('logtest') 2 .define(function (ns) { 3 console.log(2); 4 ns.provide({ 5 log : function () { console.log(3); } 6 }); 7 }); 8 9 console.log(4); 10 11 Namespace 12 .use('logtest') 13 .apply( function (ns) { 14 console.log(5); 15 ns.logtest.log(); 16 });
1:Namespace('logtest') => new NamespaceDefinition(NamespaceObjectFactory.create('logtest'))
即生成一个NamespaceDefinition对象,该对象是由NamespaceObject对象来初始化的,该对象同时还有三个属性,Object,Definition,Proc。其值依次为 NamespaceObjectFactory,NamespaceDefinition,createProcedure函数对象类。Namespace('logtest') 返回的结果就是生成的NamespaceDefinition对象,然后调用其define方法,初始化defineCallback。此时仅仅是定义,不做具体的动作。
166 define: function(callback){ 167 var nsDef = this, nsObj = this.namespaceObject; 168 this.defineCallback = function($c) { // 给defineCallback赋值,同时定义一下该回调函数的上下文,nsDef和nsObj两个对象。 169 var ns = { 170 provide : function(obj){ 171 nsObj.merge(obj); 172 $c(); 173 } 174 }; 175 merge(ns, nsDef.getStash()); 176 merge(ns, nsObj.getStash()); 177 callback(ns); 178 }; 179 },
2:使用之前定义的namespace里面的对象,Namespace.use() => Namespace().use() => Namespace('main').use()。调用use的时候初始化requires数组。
131 use: function(syntax){ // 使用namespace 132 this.useList.push(syntax); // 该namespace字符串存入数组useList 133 var splitted = syntax.split(/\s+/); // namespace和它的对象使用空格分开 134 var fqn = splitted[0]; // 取得namespace 135 var importName = splitted[1]; // 取得namespace中的对象 136 _assertValidFQN(fqn); 137 this.requires.push(function($c){ // 放一个函数到requires数组中 138 var context = this; 139 var require = NamespaceObjectFactory.create(fqn); // 获取指定的NamespaceObject对象,之前生成过得对象可以直接从缓存中获取 140 require.call(this,function(state){ // 调用NamespaceObject对象的call方法 141 context.loadImport(require,importName); 142 $c(); 143 }); 144 }); 145 return this; 146 },
3:调用main的apply方法。看一下具体的apply方法
186 apply: function(callback){ 187 var nsDef = this; 188 createProcedure(nsDef.requires) 189 .next(nsDef.defineCallback) 190 .call(nsDef,function(){ 191 callback( nsDef.getStash() ); 192 }); 193 }
取出requires数组里面的对象生成Proc对象,并把该requires数组里的对象入队列steps中,还有nsDef.defineCallback也入队列(此例中为undefined),调用Proc的call方法。第一个参数是nsDef,第二个参数是回调函数。
具体使用方法:
在定义Namespace的时候,所有的定义放在define里面,并且以匿名函数的形式定义。function (ns) { // 具体的实现 // 定义对外公开的对象,外部在use该nsName之后,就可以通过ns.nsName.key()来调用它 ns.provide({ key : value});}
使用namespace.js的好处,所有的定义都是在需要的时候才开始执行的,也就是在具体使用的时候才开始解析定义。
ps:具体内部调用关系还是没有弄明白,今后有时间再整理,这篇太乱了。
相关文章推荐
- Javascript的命名空间库----namespace.js
- namespace.js Javascript的命名空间库
- JavaScript 实现命名空间(namespace)的最佳方案——兼容主流的定义类(class)的方法,兼容所有浏览器,支持用JSDuck生成文档
- JavaScript--JS操作属性注意的命名规则
- JS--命名空间的理解(namespace)
- 浅析JavaScript中命名空间namespace模式
- JS--命名空间的理解(namespace)
- js命名空间的函数namespace
- Javascript中实现JS文件的导入+命名前缀
- 浅析JavaScript中命名空间namespace模式
- JavaScript创建命名空间(namespace)的最简实现
- JavaScript创建命名空间(namespace)的最简实现
- 关于javascript模块和命名空间(Module and namespace)
- JS--命名空间的理解(namespace)
- JS中命名空间(namespace)的概念和使用
- JS命名空间(namespace)
- JS命名空间(namespace)
- JavaScript-JS命名空间的构造和实现-[web前端开发]
- Javascript必须掌握的js库
- javascript Date format(js日期格式化)