Home  >  Article  >  Web Front-end  >  namespace.js Javascript的命名空间库_javascript技巧

namespace.js Javascript的命名空间库_javascript技巧

WBOY
WBOYOriginal
2016-05-16 18:01:01857browse

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";
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;i104 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;i152 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 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;i60 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";
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;i104 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;i152 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 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 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:具体内部调用关系还是没有弄明白,今后有时间再整理,这篇太乱了。
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn