Github: https://github.com/hirokidaichi/namespace-js
Define the Namespace object:
Var Namespace
Now let's take a look at the definition of the Namespace object. It is a NamespaceDefinition object. This Object is a function Object (the constructor of the NamespaceDefinition Object. If no parameter is provided, a main namespace is generated by default). There are three attributes: Object, Definition, and Proc. The values are sequential NamespaceObjectFactory, NamespaceDefinition, and createProcedure function object classes.
Copy codeThe Code is as follows:
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: generate a NamespaceObject object based on fqn.
The NamespaceObjectFactory object has only one create method. The parameter is the namespace Name (Fully Qualified Name ). This method has a closure environment where a cache variable is used to cache all generated NamespaceObject objects.
A NamespaceObject object contains three attributes: stash (record the current namespace), fqn (namespace name), and proc (createProcedure object ). The methods include enqueue, call, valueof, merge, getStash, and getExport.
Copy codeThe Code is as follows:
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:
This object includes five attributes: namespaceObject, requires, useList, stash, and defineCallback. Related methods are provided: use, _ mergeStashWithNS, loadImport, define, getStash, valueOf, apply
This object is the core of the namespace library and provides all the required methods.
During initialization, append a function object to the steps queue of proc of NamespaceObject, which calls the apply method.
Copy codeThe Code is as follows:
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: This object is a function object that returns the result of the next method of the Procedure object.
Procedure:
The Procedure object has three attributes: state, steps, and _ status (init by default ). The following methods are provided: next, isRunnig, enqueue, dequeue, call, And _ invoke.
Copy codeThe Code is as follows:
1 var Namespace = (function (){
2/* utility */
3 var merge = function (target, source) {// copy all source attributes to target and return target object 4 for (var p in source)
5 if (source. hasOwnProperty (p) target [p] = source [p];
6 return target;
7 };
8 var _ assertValidFQN = function (fqn) {// verify the namespace name validity. It must be a lowercase English number, underline, and dot.
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: {}, // status
15 steps: [], // storage status Array
16 _ status: 'init'
17 });
18 };
19 merge (Procedure. prototype ,{
20 next: function (state) {// if the state has a value, store it at the end of the steps queue and return this
21 if (state) this. enqueue (state );
22 return this;
23 },
24 isRunning: function () {// determines whether it is in the running status
25 return (this. _ status === 'running ');
26 },
27 enqueue: function (state) {// here, we use an array of steps to simulate the queue. The enqueue is to enter the queue from the end of the queue.
28 this. steps. push (state );
29 },
30 dequeue: function () {// dequeue is an outgoing queue
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 | |{}; // Save the current state (NamespaceDefinition object)
37 this. enqueue (function ($ c) {// function inbound queue steps
38 $ c (); // execute the passed Function
39 if (callback) callback (this); // if a callback function exists, run the callback function.
40 });
41 this. _ status = 'running'; // set the status to running.
42 this. _ invoke (); // call _ invoke
43 },
44 _ invoke: function (){
45 var _ self = this;
46 var step = _ self. dequeue (); // object output queue (FIFO)
47 if (! Step ){
48 _ self. _ status = 'finished'; // If the queue is empty, set the status to finished.
49 return;
50} // If the step is an array, skip this path.
51 if (step. call) {// if the object is a function object, execute the call method and specify the internal value of this as _ self. state, the callback function continues to call _ 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 (); // if the array length is 0, call _ invoke
59 for (var I = 0, l = step. length; I <l; I ++) {// call the respective call method for all objects (function objects) in the array, and specify this of the respective functions as _ self. state object (nsDef object)
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) {// use namespace
132 this. useList. push (syntax); // Save the namespace string to the array useList
133 var splitted = syntax. split (/\ s +/); // use spaces to separate namespace from its objects
134 var fqn = splitted [0]; // obtain the namespace
135 var importName = splitted [1]; // get the object in namespace
136 _ assertValidFQN (fqn );
137 this. requires. push (function ($ c) {// put a function into the requires Array
138 var context = this;
139 var require = NamespaceObjectFactory. create (fqn); // obtain the specified NamespaceObject. previously generated objects can be obtained directly from the cache.
140 require. call (this, function (state) {// call the call method of the NamespaceObject object
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) {// assign a value to defineCallback and define the context of the callback function, nsDef and 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 })();
Append the method supported by Namespace:
Namespace. use
Namespace. fromInternal
Namespace. GET
Namespace. fromExternal
Copy codeThe Code is as follows:
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 ){}
Let's take an example:
Copy codeThe Code is as follows:
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 '))
That is, a NamespaceDefinition Object is generated. This Object is initialized by the NamespaceObject Object. This Object also has three attributes, Object, Definition, and Proc. The values are sequential NamespaceObjectFactory, NamespaceDefinition, and createProcedure function object classes. The result returned by Namespace ('logtest') is the generated NamespaceDefinition object, and then calls its define method to initialize defineCallback. At this time, it is just a definition, not a specific action.
Copy codeThe Code is as follows:
166 define: function (callback ){
167 var nsDef = this, nsObj = this. namespaceObject;
168 this. defineCallback = function ($ c) {// assign a value to defineCallback and define the context of the callback function, nsDef and 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: use the objects in the previously defined namespace, Namespace. use () => Namespace (). use () => Namespace ('main'). use (). Initialize the requires array when you call use.
Copy codeThe Code is as follows:
131 use: function (syntax) {// use namespace
132 this. useList. push (syntax); // Save the namespace string to the array useList
133 var splitted = syntax. split (/\ s +/); // use spaces to separate namespace from its objects
134 var fqn = splitted [0]; // obtain the namespace
135 var importName = splitted [1]; // get the object in namespace
136 _ assertValidFQN (fqn );
137 this. requires. push (function ($ c) {// put a function into the requires Array
138 var context = this;
139 var require = NamespaceObjectFactory. create (fqn); // obtain the specified NamespaceObject. previously generated objects can be obtained directly from the cache.
140 require. call (this, function (state) {// call the call method of the NamespaceObject object
141 context. loadImport (require, importName );
142 $ c ();
143 });
144 });
145 return this;
146 },
3: Call the apply method of main. Take a look at the specific apply Method
Copy codeThe Code is as follows:
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}
Get the objects in the requires array to generate the Proc object, and put the objects in the requires array into the queue steps, and nsDef. defineCallback is also in the queue (undefined in this example) and calls the call method of Proc. The first parameter is nsDef, and the second parameter is the callback function.
Usage:
When defining a Namespace, all definitions are placed in define and defined in the form of anonymous functions. Function (ns) {// specific implementation // defines the object to be made public to the outside. After using the nsName, you can use ns. nsName. key () to call it ns. provide ({key: value });}
The benefit of using namespace. js is that all definitions are executed only when necessary, that is, definitions are parsed only when specific use is made.
Ps: The specific internal call relationship is still unclear. It will be too messy to sort out it in the future.