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 相关文章推荐
jQuery 美元符冲突的解决方法
Mar 28 Javascript
js获取光标位置和设置文本框光标位置示例代码
Jan 09 Javascript
jquery操作checkbox示例分享
Jul 21 Javascript
轻量级jQuery插件slideBox实现带底栏轮播(焦点图)代码
Mar 28 Javascript
JS实现列表的响应式排版(推荐)
Sep 01 Javascript
VUE 更好的 ajax 上传处理 axios.js实现代码
May 10 Javascript
Javacript中自定义的map.js  的方法
Nov 26 Javascript
JavaScript创建对象的常用方式总结
Aug 10 Javascript
layui问题之模拟select点击事件的实例讲解
Aug 15 Javascript
在Angular中使用JWT认证方法示例
Sep 10 Javascript
vue-better-scroll 的使用实例代码详解
Dec 03 Javascript
详解element-ui级联菜单(城市三级联动菜单)和回显问题
Oct 02 Javascript
基于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
用php实现的获取网页中的图片并保存到本地的代码
2010/01/05 PHP
PHP乱码问题,UTF-8乱码常见问题小结
2012/04/09 PHP
PHP判断是否有Get参数的方法
2014/05/05 PHP
php通过记录IP来防止表单重复提交方法分析
2014/12/16 PHP
php socket通信(tcp/udp)实例分析
2016/02/14 PHP
Thinkphp 中 distinct 的用法解析
2016/12/14 PHP
常规表格多表头查询示例
2014/02/21 Javascript
js中自定义方法实现停留几秒sleep
2014/07/11 Javascript
60行js代码实现俄罗斯方块
2015/03/31 Javascript
JS简单编号生成器实现方法(附demo源码下载)
2016/04/05 Javascript
js实现延迟加载的几种方法
2017/04/24 Javascript
AngularJS实现动态切换样式的方法分析
2018/06/26 Javascript
Element InputNumber计数器的使用方法
2020/07/27 Javascript
详解Python的Django框架中的Cookie相关处理
2015/07/22 Python
python中安装模块包版本冲突问题的解决
2017/05/02 Python
详解Python核心编程中的浅拷贝与深拷贝
2018/01/07 Python
Python微信公众号开发平台
2018/01/25 Python
python实现将excel文件转化成CSV格式
2018/03/22 Python
pandas.DataFrame.to_json按行转json的方法
2018/06/05 Python
django 连接数据库 sqlite的例子
2019/08/14 Python
python实现代码统计器
2019/09/19 Python
Python 中pandas索引切片读取数据缺失数据处理问题
2019/10/09 Python
Python字典取键、值对的方法步骤
2020/09/30 Python
python uuid生成唯一id或str的最简单案例
2021/01/13 Python
Belvilla德国:在线预订度假屋
2018/04/10 全球购物
玛蒂尔达简服装:Matilda Jane Clothing
2019/02/13 全球购物
会计电算化个人求职信范文
2014/01/24 职场文书
建议书标准格式
2014/03/12 职场文书
搞笑创意广告语
2014/03/17 职场文书
销售员岗位职责
2014/06/09 职场文书
先进集体申报材料
2014/12/25 职场文书
学生党员检讨书范文
2014/12/27 职场文书
医生辞职信范文
2015/03/02 职场文书
2015年音乐教师个人工作总结
2015/05/20 职场文书
故意伤害辩护词
2015/05/21 职场文书
python 如何在list中找Topk的数值和索引
2021/05/20 Python