namespace.js Javascript的命名空间库


Posted in Javascript onOctober 11, 2011

github:https://github.com/hirokidaichi/namespace-js
定义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 }; 
73 
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 })(); 
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 }); 
195 
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 }); 
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 相关文章推荐
JS判断元素为数字的奇异写法分享
Aug 01 Javascript
js怎么终止程序return不行换jfslk
May 30 Javascript
父节点获取子节点的字符串示例代码
Feb 26 Javascript
JS实现“隐藏与显示”功能(多种方法)
Nov 24 Javascript
Js apply方法详解
Feb 16 Javascript
JS仿JQuery选择器功能
Mar 08 Javascript
vue元素实现动画过渡效果
Jul 01 Javascript
node.js调用C++函数的方法示例
Sep 21 Javascript
一个Java程序猿眼中的前后端分离以及Vue.js入门(推荐)
Apr 19 Javascript
JS如何实现网站中PC端和手机端自动识别并跳转对应的代码
Jan 08 Javascript
JS数组push、unshift、pop、shift方法的实现与使用方法示例
Apr 29 Javascript
详解vite+ts快速搭建vue3项目以及介绍相关特性
Feb 25 Vue.js
基于jquery的当鼠标滚轮到最底端继续加载新数据思路分享(多用于微博、空间、论坛 )
Oct 10 #Javascript
jquery.tmpl JQuery模板插件
Oct 10 #Javascript
brook javascript框架介绍
Oct 10 #Javascript
jQuery 一个图片切换的插件
Oct 09 #Javascript
跨域请求之jQuery的ajax jsonp的使用解惑
Oct 09 #Javascript
多浏览器兼容性比较好的复制到剪贴板的js代码
Oct 09 #Javascript
jquery利用event.which方法获取键盘输入值的代码
Oct 09 #Javascript
You might like
深入Nginx + PHP 缓存详解
2013/07/11 PHP
JoshChen_web格式编码UTF8-无BOM的小细节分析
2013/08/16 PHP
php使用PDO操作MySQL数据库实例
2014/12/30 PHP
PHP中JSON的应用技巧
2015/10/10 PHP
php如何获取文件的扩展名
2015/10/28 PHP
JQery jstree 大数据量问题解决方法
2010/03/09 Javascript
javascript最常用与实用的创建类的代码
2010/08/12 Javascript
javascript实现在某个元素上阻止鼠标右键事件的方法和实例
2014/08/12 Javascript
Node.js的特点和应用场景介绍
2014/11/04 Javascript
javascript事件模型实例分析
2015/01/30 Javascript
jQuery通过ajax请求php遍历json数组到table中的代码(推荐)
2016/06/12 Javascript
JS实现iframe自适应高度的方法示例
2017/01/07 Javascript
10 种最常见的 Javascript 错误(频率最高)
2018/02/08 Javascript
Javascript的console['']常用输入方法汇总
2018/04/26 Javascript
ionic使用angularjs表单验证(模板验证)
2018/12/12 Javascript
vue + element-ui的分页问题实现
2018/12/17 Javascript
js中对象和面向对象与Json介绍
2019/01/21 Javascript
js如何实现元素曝光上报
2019/08/07 Javascript
从零学python系列之数据处理编程实例(二)
2014/05/22 Python
Python中使用第三方库xlrd来写入Excel文件示例
2015/04/05 Python
Python队列的定义与使用方法示例
2017/06/24 Python
Python Requests库基本用法示例
2018/08/20 Python
Django框架 信号调度原理解析
2019/09/04 Python
python中调试或排错的五种方法示例
2019/09/12 Python
通过python扫描二维码/条形码并打印数据
2019/11/14 Python
python 代码运行时间获取方式详解
2020/09/18 Python
HTML5中的新元素介绍
2008/10/17 HTML / CSS
SEPHORA新西兰官方网站:购买化妆品和护肤品
2016/12/02 全球购物
法国体育用品商店:GO Sport
2019/10/23 全球购物
超市采购员岗位职责
2014/02/01 职场文书
比赛口号大全
2014/06/10 职场文书
办公室岗位职责
2015/02/04 职场文书
导游词之澳门妈祖庙
2019/12/19 职场文书
php实现自动生成验证码的实例讲解
2021/11/17 PHP
浅谈Node的内存泄露问题
2022/05/06 NodeJs
linux目录管理方法介绍
2022/06/01 Servers