zl程序教程

您现在的位置是:首页 >  其它

当前栏目

namespace.jsJavascript的命名空间库

空间 命名 Namespace
2023-06-13 09:14:30 时间
github:https://github.com/hirokidaichi/namespace-js
定义Namespace对象:
varNamespace
现在来具体看一下Namespace对象的定义,它是一个NamespaceDefinition对象。该对象是一个函数对象(NamespaceDefinition对象的构造函数,如果不给参数的话就默认生成一个main的命名空间),还有三个属性,Object,Definition,Proc。其值依次为NamespaceObjectFactory,NamespaceDefinition,createProcedure函数对象类。
复制代码代码如下:

196varcreateNamespace=function(fqn){
197returnnewNamespaceDefinition(
198NamespaceObjectFactory.create(fqn||"main")
199);
200};
201merge(createNamespace,{
202"Object":NamespaceObjectFactory,
203Definition:NamespaceDefinition,
204Proc:createProcedure
205});

NamespaceObjectFactory:根据fqn生成NamespaceObject对象。
NamespaceObjectFactory对象只有一个create方法,参数就是命名空间的名字(FullyQualifiedName)。该方法有一个闭包环境,该环境里有一个cache变量用于缓存所有生成的NamespaceObject对象。
一个NamespaceObject对象包含有三个属性,stash(记录当前namespace),fqn(namespace名字),proc(createProcedure对象)。方法包括:enqueue,call,valueof,merge,getStash,getExport
复制代码代码如下:

74varNamespaceObject=function_Private_Class_Of_NamespaceObject(fqn){
75merge(this,{
76stash:{CURRENT_NAMESPACE:fqn},
77fqn:fqn,
78proc:createProcedure()
79});
80};
81merge(NamespaceObject.prototype,{
82enqueue:function(context){
83this.proc.next(context);
84},
85call:function(state,callback){
86this.proc.call(state,callback);
87},
88valueOf:function(){
89return"#NamespaceObject<"+this.fqn+">";
90},
91merge:function(obj){
92merge(this.stash,obj);
93returnthis;
94},
95getStash:function(){
96returnthis.stash;
97},
98getExport:function(importName){
99if(importName==="*")returnthis.stash;
100
101varimportNames=importName.split(/,/),
102retStash={};
103for(vari=0,l=importNames.length;i<l;i++){
104retStash[importNames[i]]=this.stash[importNames[i]];
105}
106returnretStash;
107}
108});
109varNamespaceObjectFactory=(function(){
110varcache={};
111return{
112create:function(fqn){
113_assertValidFQN(fqn);
114return(cache[fqn]||(cache[fqn]=newNamespaceObject(fqn)));
115}
116};
117})();

NamespaceDefinition:
该对象包括5个属性,namespaceObject,requires,useList,stash,defineCallback。并提供了相关的方法:use,_mergeStashWithNS,loadImport,define,getStash,valueOf,apply
该对象是namespace库的核心,它提供了所有需要的方法。
初始化的时候,在NamespaceObject的proc的steps队列里追加一个函数对象,该函数将调用apply方法。
复制代码代码如下:
119varNamespaceDefinition=function_Private_Class_Of_NamespaceDefinition(nsObj){
120merge(this,{
121namespaceObject:nsObj,
122requires:[],
123useList:[],
124stash:{},
125defineCallback:undefined
126});
127var_self=this;
128nsObj.enqueue(function($c){_self.apply($c);});
129};
130merge(NamespaceDefinition.prototype,{
131use:function(syntax){
132this.useList.push(syntax);
133varsplitted=syntax.split(/\s+/);
134varfqn=splitted[0];
135varimportName=splitted[1];
136_assertValidFQN(fqn);
137this.requires.push(function($c){
138varcontext=this;
139varrequire=NamespaceObjectFactory.create(fqn);
140require.call(this,function(state){
141context.loadImport(require,importName);
142$c();
143});
144});
145returnthis;
146},
147_mergeStashWithNS:function(nsObj){
148varnsList=nsObj.fqn.split(/\./);
149varcurrent=this.getStash();
150
151for(vari=0,l=nsList.length;i<l-1;i++){
152if(!current[nsList[i]])current[nsList[i]]={};
153current=current[nsList[i]];
154}
155
156varlastLeaf=nsList[nsList.length-1];
157current[lastLeaf]=merge(current[lastLeaf]||{},nsObj.getStash());
158},
159loadImport:function(nsObj,importName){
160if(importName){
161merge(this.stash,nsObj.getExport(importName));
162}else{
163this._mergeStashWithNS(nsObj);
164}
165},
166define:function(callback){
167varnsDef=this,nsObj=this.namespaceObject;
168this.defineCallback=function($c){
169varns={
170provide:function(obj){
171nsObj.merge(obj);
172$c();
173}
174};
175merge(ns,nsDef.getStash());
176merge(ns,nsObj.getStash());
177callback(ns);
178};
179},
180getStash:function(){
181returnthis.stash;
182},
183valueOf:function(){
184return"#NamespaceDefinition<"+this.namespaceObject+">uses:"+this.useList.join(",");
185},
186apply:function(callback){
187varnsDef=this;
188createProcedure(nsDef.requires)
189.next(nsDef.defineCallback)
190.call(nsDef,function(){
191callback(nsDef.getStash());
192});
193}
194});

createProcedure:该对象是一个函数对象,返回Procedure对象的next方法的结果。
Procedure:
Procedure对象有三个属性:state,steps,_status(默认为init)。提供一下几种方法:next,isRunnig,enqueue,dequeue,call,_invoke。

复制代码代码如下:
1varNamespace=(function(){
2/*utility*/
3varmerge=function(target,source){//把source的所有自身属性copy到target中去,并返回target对象4for(varpinsource)
5if(source.hasOwnProperty(p))target[p]=source[p];
6returntarget;
7};
8var_assertValidFQN=function(fqn){//验证namespace名字的有效性,必须是小写英数字,下划线和点
9if(!(/^[a-z0-9_.]+/).test(fqn))throw("invalidnamespace");
10};
11
12varProcedure=function_Private_Class_Of_Proc(){
13merge(this,{
14state:{},//状态
15steps:[],//存储状态的数组
16_status:"init"
17});
18};
19merge(Procedure.prototype,{
20next:function(state){//如果state有值,存入到steps队列队尾,然后返回this
21if(state)this.enqueue(state);
22returnthis;
23},
24isRunning:function(){//判定是否为running状态
25return(this._status==="running");
26},
27enqueue:function(state){//这里其实是用数组steps来模拟队列,enqueue就是从队尾入队列
28this.steps.push(state);
29},
30dequeue:function(){//dequeue就是从对头出队列
31returnthis.steps.shift();
32},
33call:function(initialState,callback){//
34if(this.isRunning())throw("donotruntwice");
35
36this.state=initialState||{};//保存当前state(NamespaceDefinition对象)
37this.enqueue(function($c){//函数入队列steps
38$c();//执行传进来的函数
39if(callback)callback(this);//如果存在回调函数的,执行回调函数
40});
41this._status="running";//设置状态为running
42this._invoke();//调用_invoke
43},
44_invoke:function(){
45var_self=this;
46varstep=_self.dequeue();//对象出队列(FIFO)
47if(!step){
48_self._status="finished";//如果队列为空,则设置状态为finished
49return;
50}//step是数组的情况下不走这条路径
51if(step.call){//如果该对象是函数对象的时候,则执行该call方法,并指定内部this为_self.state,回调函数里面继续调用_invoke
52returnstep.call(_self.state,function_cont(state){
53if(state)_self.state=state;
54_self._invoke();
55});
56}
57varfinishedProcess=0;
58if(step.length===0)_self._invoke();//如果该数组长度为0,则调用_invoke
59for(vari=0,l=step.length;i<l;i++){//针对数组里的所有对象(函数对象)调用各自的call方法,并指定各自函数的this为_self.state对象(nsDef对象)
60step[i].call(_self.state,function_joinWait(){
61finishedProcess++;
62if(finishedProcess==l){
63_self._invoke();
64}
65});
66}
67}
68});
69
70varcreateProcedure=function(state){
71returnnewProcedure().next(state);
72};
73
74varNamespaceObject=function_Private_Class_Of_NamespaceObject(fqn){
75merge(this,{
76stash:{CURRENT_NAMESPACE:fqn},
77fqn:fqn,
78proc:createProcedure()
79});
80};
81merge(NamespaceObject.prototype,{
82enqueue:function(context){
83this.proc.next(context);
84},
85call:function(state,callback){
86this.proc.call(state,callback);
87},
88valueOf:function(){
89return"#NamespaceObject<"+this.fqn+">";
90},
91merge:function(obj){
92merge(this.stash,obj);
93returnthis;
94},
95getStash:function(){
96returnthis.stash;
97},
98getExport:function(importName){
99if(importName==="*")returnthis.stash;
100
101varimportNames=importName.split(/,/),
102retStash={};
103for(vari=0,l=importNames.length;i<l;i++){
104retStash[importNames[i]]=this.stash[importNames[i]];
105}
106returnretStash;
107}
108});
109varNamespaceObjectFactory=(function(){
110varcache={};
111return{
112create:function(fqn){
113_assertValidFQN(fqn);
114return(cache[fqn]||(cache[fqn]=newNamespaceObject(fqn)));
115}
116};
117})();
118
119varNamespaceDefinition=function_Private_Class_Of_NamespaceDefinition(nsObj){
120merge(this,{
121namespaceObject:nsObj,
122requires:[],
123useList:[],
124stash:{},
125defineCallback:undefined
126});
127var_self=this;
128nsObj.enqueue(function($c){_self.apply($c);});
129};
130merge(NamespaceDefinition.prototype,{
131use:function(syntax){//使用namespace
132this.useList.push(syntax);//该namespace字符串存入数组useList
133varsplitted=syntax.split(/\s+/);//namespace和它的对象使用空格分开
134varfqn=splitted[0];//取得namespace
135varimportName=splitted[1];//取得namespace中的对象
136_assertValidFQN(fqn);
137this.requires.push(function($c){//放一个函数到requires数组中
138varcontext=this;
139varrequire=NamespaceObjectFactory.create(fqn);//获取指定的NamespaceObject对象,之前生成过得对象可以直接从缓存中获取
140require.call(this,function(state){//调用NamespaceObject对象的call方法
141context.loadImport(require,importName);
142$c();
143});
144});
145returnthis;
146},
147_mergeStashWithNS:function(nsObj){
148varnsList=nsObj.fqn.split(/\./);
149varcurrent=this.getStash();
150
151for(vari=0,l=nsList.length;i<l-1;i++){
152if(!current[nsList[i]])current[nsList[i]]={};
153current=current[nsList[i]];
154}
155
156varlastLeaf=nsList[nsList.length-1];
157current[lastLeaf]=merge(current[lastLeaf]||{},nsObj.getStash());
158},
159loadImport:function(nsObj,importName){
160if(importName){
161merge(this.stash,nsObj.getExport(importName));
162}else{
163this._mergeStashWithNS(nsObj);
164}
165},
166define:function(callback){
167varnsDef=this,nsObj=this.namespaceObject;
168this.defineCallback=function($c){//给defineCallback赋值,同时定义一下该回调函数的上下文,nsDef和nsObj两个对象。
169varns={
170provide:function(obj){
171nsObj.merge(obj);
172$c();
173}
174};
175merge(ns,nsDef.getStash());
176merge(ns,nsObj.getStash());
177callback(ns);
178};
179},
180getStash:function(){
181returnthis.stash;
182},
183valueOf:function(){
184return"#NamespaceDefinition<"+this.namespaceObject+">uses:"+this.useList.join(",");
185},
186apply:function(callback){
187varnsDef=this;
188createProcedure(nsDef.requires)
189.next(nsDef.defineCallback)
190.call(nsDef,function(){
191callback(nsDef.getStash());
192});
193}
194});
195
196varcreateNamespace=function(fqn){
197returnnewNamespaceDefinition(
198NamespaceObjectFactory.create(fqn||"main")
199);
200};
201merge(createNamespace,{
202"Object":NamespaceObjectFactory,
203Definition:NamespaceDefinition,
204Proc:createProcedure
205});
206returncreateNamespace;
207})();

追加定义Namespace支持的方法:
Namespace.use
Namespace.fromInternal
Namespace.GET
Namespace.fromExternal
复制代码代码如下:
1Namespace.use=function(useSyntax){returnNamespace().use(useSyntax);}
2Namespace.fromInternal=Namespace.GET=(function(){
3varget=(function(){
4varcreateRequester=function(){
5varxhr;
6try{xhr=newXMLHttpRequest()}catch(e){
7try{xhr=newActiveXObject("Msxml2.XMLHTTP.6.0")}catch(e){
8try{xhr=newActiveXObject("Msxml2.XMLHTTP.3.0")}catch(e){
9try{xhr=newActiveXObject("Msxml2.XMLHTTP")}catch(e){
10try{xhr=newActiveXObject("Microsoft.XMLHTTP")}catch(e){
11thrownewError("ThisbrowserdoesnotsupportXMLHttpRequest.")
12}
13}
14}
15}
16}
17returnxhr;
18};
19varisSuccessStatus=function(status){
20return(status>=200&&status<300)||
21status==304||
22status==1223||
23(!status&&(location.protocol=="file:"||location.protocol=="chrome:"));
24};
25
26returnfunction(url,callback){
27varxhr=createRequester();
28xhr.open("GET",url,true);
29xhr.onreadystatechange=function(){
30if(xhr.readyState===4){
31if(isSuccessStatus(xhr.status||0)){
32callback(true,xhr.responseText);
33}else{
34callback(false);
35}
36}
37};
38xhr.send("")
39};
40})();
41
42returnfunction(url,isManualProvide){
43returnfunction(ns){
44get(url,function(isSuccess,responseText){
45if(isSuccess){
46if(isManualProvide)
47returneval(responseText);
48else
49returnns.provide(eval(responseText));
50}else{
51varpub={};
52pub[url]="loadingerror";
53ns.provide(pub);
54}
55});
56};
57};
58})();
59
60Namespace.fromExternal=(function(){
61varcallbacks={};
62varcreateScriptElement=function(url,callback){
63varscriptElement=document.createElement("script");
64
65scriptElement.loaded=false;
66
67scriptElement.onload=function(){
68this.loaded=true;
69callback();
70};
71scriptElement.onreadystatechange=function(){
72if(!/^(loaded|complete)$/.test(this.readyState))return;
73if(this.loaded)return;
74scriptElement.loaded=true;
75callback();
76};
77scriptElement.src=url;
78document.body.appendChild(scriptElement);
79returnscriptElement.src;
80};
81vardomSrc=function(url){
82returnfunction(ns){
83varsrc=createScriptElement(url,function(){
84varname=ns.CURRENT_NAMESPACE;
85varcb=callbacks[name];
86deletecallbacks[name];
87cb(ns);
88});
89}
90};
91domSrc.registerCallback=function(namespace,callback){
92callbacks[namespace]=callback;
93};
94returndomSrc;
95})();
96
97try{module.exports=Namespace;}catch(e){}

具体看一个例子:
复制代码代码如下:
1Namespace("logtest")
2.define(function(ns){
3console.log(2);
4ns.provide({
5log:function(){console.log(3);}
6});
7});
8
9console.log(4);
10
11Namespace
12.use("logtest")
13.apply(function(ns){
14console.log(5);
15ns.logtest.log();
16});


1:Namespace("logtest")=>newNamespaceDefinition(NamespaceObjectFactory.create("logtest"))
即生成一个NamespaceDefinition对象,该对象是由NamespaceObject对象来初始化的,该对象同时还有三个属性,Object,Definition,Proc。其值依次为NamespaceObjectFactory,NamespaceDefinition,createProcedure函数对象类。Namespace("logtest")返回的结果就是生成的NamespaceDefinition对象,然后调用其define方法,初始化defineCallback。此时仅仅是定义,不做具体的动作。

复制代码代码如下:
166define:function(callback){
167varnsDef=this,nsObj=this.namespaceObject;
168this.defineCallback=function($c){//给defineCallback赋值,同时定义一下该回调函数的上下文,nsDef和nsObj两个对象。
169varns={
170provide:function(obj){
171nsObj.merge(obj);
172$c();
173}
174};
175merge(ns,nsDef.getStash());
176merge(ns,nsObj.getStash());
177callback(ns);
178};
179},

2:使用之前定义的namespace里面的对象,Namespace.use()=>Namespace().use()=>Namespace("main").use()。调用use的时候初始化requires数组。

复制代码代码如下:
131use:function(syntax){//使用namespace
132this.useList.push(syntax);//该namespace字符串存入数组useList
133varsplitted=syntax.split(/\s+/);//namespace和它的对象使用空格分开
134varfqn=splitted[0];//取得namespace
135varimportName=splitted[1];//取得namespace中的对象
136_assertValidFQN(fqn);
137this.requires.push(function($c){//放一个函数到requires数组中
138varcontext=this;
139varrequire=NamespaceObjectFactory.create(fqn);//获取指定的NamespaceObject对象,之前生成过得对象可以直接从缓存中获取
140require.call(this,function(state){//调用NamespaceObject对象的call方法
141context.loadImport(require,importName);
142$c();
143});
144});
145returnthis;
146},

3:调用main的apply方法。看一下具体的apply方法
复制代码代码如下:
186apply:function(callback){
187varnsDef=this;
188createProcedure(nsDef.requires)
189.next(nsDef.defineCallback)
190.call(nsDef,function(){
191callback(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:具体内部调用关系还是没有弄明白,今后有时间再整理,这篇太乱了。