Questions about JavaScript modularity and namespace management _javascript tips

Source: Internet
Author: User
"About modularity and why to Modularize"

Let's talk about why we want to modularize. In fact, this is related to coding ideas and the convenience of code management (no mention of namespace pollution is because I believe that the coder who has considered modularity should at least have a set of its own naming laws, in small and medium-sized sites, the probability of the name space pollution is very small, but does not mean that does not exist, I'll talk about it later on.
In fact, modular thinking is still the same as object-oriented thinking, but perhaps our so-called "module" is more than the so-called "object" larger objects. By combining the functional functions dedicated to the same purpose through good encapsulation and ensuring good reusability, we can probably refer to the idea of such a composite code fragment as an object-oriented idea. There are many benefits to doing this, such as: ease of use, versatility, maintainability, readability, avoidance of variable name pollution and so on.
And modularity is nothing more than object-oriented module-oriented, we put together with the same project (module) related to the functions of packaging organically combined, through a common name to manage. It can be said to be a modular idea. So, compared to object-oriented, I think the idea of implementing modularity on the code architecture is actually easier than object-oriented implementation.
Unlike C#,java, which itself has a strong typed language with good modularity and namespace mechanisms. JavaScript does not provide any language functionality for creating and managing modules. Because of this, we are doing JS coding some time, for the so-called namespace (namespace) use will appear somewhat too casual (including myself). Like what:
Copy Code code as follows:

var Hongru = {}//Namespace

(function () {
Hongru.class1 = function () {
Todo
}
...
Hongru.class2 = function () {
Todo
}
})();


As above, we usually use a global variable or global object as our namespace, so simple that it even seems to be a bit of a trivial committee with its so important responsibility. But can we say it's not good? Can not, but feel that can have this coding habits of students should be worthy of praise ...


So, when we are doing some projects or building some small scale sites, the simple way to do namespace work is enough, basically nothing big trouble. But return to the essence, if there is code cleanliness or build a large-scale site, or at the outset with an absolutely elegant attitude and logic to do the code structure. Maybe we should consider a better way to register and manage the namespace.
In this respect, jquery compared to yui,mootool,ext etc, it appears lesser, (although JQ also has its own set of modular mechanism), but this still does not hinder our love for it, after all, the emphasis is different, JQ strong is strong in its selector, otherwise he will not be called J-query.
So it's not unreasonable to say that jquery is more suitable for small and medium sized sites. Just like watercress's open source front-end lightweight frame do framework, it is also built on jquery, encapsulating the idea of a layer of modular management and the function of file synchronization loading.

"About Namespace"

Okay, we return to the topic, such as on the way, simple through the global object to do namespace has been able to reduce the global variable, to avoid the problem of variable name pollution, but once the site is larger, or many projects, the name space to manage multiple global objects will still have problems. If a name conflict happens, a module overwrites the properties of another module, causing one or both of them to not work properly. And after the problem, it's troublesome to go to the screening. So we may need a mechanism or a tool that can tell if there is a duplicate name when creating a namespace.

On the other hand, different modules, that is, different namespace can not be completely independent, sometimes we also need to create a different namespace under the same method or attribute, when the method or attribute import and export will also be a problem.

In the above two aspects, I thought a little bit, did some tests, but still some flaws. Today again the "Rhino book", is worthy of the classic, the above problem, it is easy to solve. Based on the "Rhino Book" Solution and demo, I made some changes and simplified it slightly. Share your own understanding. There are several points that are more important:

--Test the availability of each child module

Since our namespaces are an object and have hierarchical relationships with objects, it is important to detect and register the availability of namespaces based on such hierarchical relationships, especially when registering a namespace (sub-namespace). For example, we registered a new name space for Hongru, then we need to register a namespace for hongru.me, that is, we are meant to be me this namespace is Hongru Sub-namespace, they should have a father-son relationship. So, when registering a namespace, you need to pass '. ' To split, and to make a corresponding judgment. So, the code that registers a namespace is probably as follows:

Copy Code code as follows:

Create namespace--> return a top namespace
Module.createnamespace = function (name, version) {
if (!name) throw new Error (' name required ');
if (Name.charat (0) = = '. ' | | Name.charat (name.length-1) = '. ' | | name.indexof ('.. ')!=-1) throw new Error (' Illegal name ' );

var parts = name.split ('. ');

var container = Module.globalnamespace;
for (var i=0; i<parts.length; i++) {
var part = Parts[i];
if (!container[part]) Container[part] = {};
container = Container[part];
}

var namespace = container;
if (namespace.name) throw new Error (' module "' +name+ '" is already defined ');
Namespace.Name = NAME;
if (version) namespace. Version = version;

Module.modules[name] = namespace;
return namespace;
};

Note: The module above is a generic module in which we register and manage namespace, which itself serves as a "base module" with a modules Module queue attribute to store our newly registered namespaces, because of this queue, We can easily judge the namespace time has been registered:


Copy Code code as follows:

var Module;
Check Module--> Make sure ' Module ' isn't existed
if (!! Module && (typeof module!= ' object ' | | Module.name)) throw new Error ("NameSpace ' Module ' already exists!");

Module = {};

Module.name = ' Module ';
Module.version = 0.1;

Module.export = [' Require ',
' Importsymbols '];

MODULE.EXPORT_OK = [' Createnamespace ',
' IsDefined ',
' Modules ',
' Globalnamespace '];

Module.globalnamespace = this;

Module.modules = {' module ': module};

The last line of code above is a namespace queue, all new namespace will be put inside. Combined with the previous piece of code, the basic can be very good management of our name space, as for module this "base module" and some other attributes such as export, and so will continue to say. The following is a test demo that creates a name space

Copy Code code as follows:

Module.createnamespace (' Hongru ', 0.1)//register a namespace named Hongru, version 0.1

The second version of the argument can also be used if you don't need the version number. We can see our newly registered name space under the Chrome-debugger.


You can see that the newly registered Hongru namespace is already in effect: Look at module queues for modules:

As you can see, the newly registered Hongru is also added to the module's modules queue. As you can see, there are several ways to Require,isdefined,importsymbols in the module.
Since the Require (detection version), isdefined (detection namespace has been registered) These two methods are not difficult, just a little bit:

--Version and duplicate name detection


Copy Code code as follows:

Check name is defined or not
module.isdefined = function (name) {
return name in Module.modules;
};
Check version
Module.require = function (name, version) {
if (!) ( Name in Module.modules)) throw the new Error (' Module ' +name+ ' is not defined ');
if (!version) return;
var n = module.modules[name];
if (!n.version | | n.version < VERSION) throw new Error (' VERSION ' +version+ ' or greater is required ');
};

The above two methods are very simple, I believe we all understand that one is the queue detection is the same name, a detection version to achieve the required version. There is no special place, it is not fine to say, slightly more complex is the name space between the attributes or methods of the introduction of the problem.
--The export of attributes or methods marked in the namespace
Because we want a generic namespace registration and management of the tool, so in the markup import or export, you need to consider the configuration, not a whole brain to import or export. So we have the export and EXPORT_OK two array in the module template that we see as the tag queue for storing properties or methods that we allow to export. Where export is public the tag queue, EXPORT_OK for us to customize the tag queue, if you do not think so clearly, you can use only a tag queue, to store the markup attributes or methods that you allow to export.
With the tag queue, the export operation we do is only for the marks in the two tag queues for export and EXPORT_OK.
Copy Code code as follows:

Import Module
Module.importsymbols = function (from) {
if (typeof form = = ' string ') from = Module.modules[from];
var to = Module.globalnamespace; Dafault
var symbols = [];
var firstsymbol = 1;
if (arguments.length>1 && typeof arguments[1] = = ' object ' && arguments[1]!= null) {
to = arguments[1];
Firstsymbol = 2;
}
for (var A=firstsymbol; a<arguments.length; a++) {
Symbols.push (Arguments[a]);
}
if (Symbols.length = = 0) {
Default Export List
if (from. EXPORT) {
for (var i=0; I<from. Export.length; i++) {
var s = from. Export[i];
To[s] = From[s];
}
Return
else if (!from. EXPORT_OK) {
EXPORT array && export_ok array both undefined
for (Var S. from) {
To[s] = From[s];
Return
}
}
}
if (Symbols.length > 0) {
var allowed;
if (from. EXPORT | | Form. EXPORT_OK) {
allowed = {};
if (from. EXPORT) {
for (var i=0; i<form. Export.length; i++) {
Allowed[from. Export[i]] = true;
}
}
if (from. EXPORT_OK) {
for (var i=0; i<form. Export_ok.length; i++) {
Allowed[form. Export_ok[i]] = true;
}
}
}
}
Import the symbols
for (var i=0; i<symbols.length; i++) {
var s = symbols[i];
if (!) ( s in from) throw new Error (' symbol ' +s+ ' isn't defined ');
if (!! Allowed &&! (s in allowed)) throw new Error (s+ ' isn't public, cannot be imported ');
To[s] = Form[s];
}
}

The first parameter in this method is the export source space, the second parameter is the import destination space (optional, the default is defined Globalnamespace), and the following parameter is optional, for the specific attributes or methods you want to export, the default is all of the tag queues.
Here is the test demo:
Copy Code code as follows:

Module.createnamespace (' Hongru ');
Module.createnamespace (' Me ', 0.1);
Me. EXPORT = [' Define ']
Me.define = function () {
this.name = ' __me ';
}
Module.importsymbols (Me, Hongru);//To import the tags under the Me namespace into the Hongru name space

You can see the test results:

The method define () that was originally defined under the Me namespace is imported into the Hongru name space. Of course, the import export here is actually just copy, which still accesses and uses the Define () method under the Me name space.

Well, about here, this demo is only to provide a way to manage the name space, there must be more perfect method, you can refer to the Yui,ext and other frameworks. or refer to the section on modules and namespaces in the JavaScript Authority Guide.

Finally post the source code:

Copy Code code as follows:

* = = = Module and NameSpace Tool-func = =
* Author:hongru.chen
* date:2010-12-05
*/
var Module;
Check Module--> Make sure ' Module ' isn't existed
if (!! Module && (typeof module!= ' object ' | | Module.name)) throw new Error ("NameSpace ' Module ' already exists!");
Module = {};
Module.name = ' Module ';
Module.version = 0.1;
Module.export = [' Require ',
' Importsymbols '];
MODULE.EXPORT_OK = [' Createnamespace ',
' IsDefined ',
' Modules ',
' Globalnamespace '];
Module.globalnamespace = this;
Module.modules = {' module ': module};
Create namespace--> return a top namespace
Module.createnamespace = function (name, version) {
if (!name) throw new Error (' name required ');
if (Name.charat (0) = = '. ' | | Name.charat (name.length-1) = '. ' | | name.indexof ('.. ')!=-1) throw new Error (' Illegal name ' );
var parts = name.split ('. ');
var container = Module.globalnamespace;
for (var i=0; i<parts.length; i++) {
var part = Parts[i];
if (!container[part]) Container[part] = {};
container = Container[part];
}
var namespace = container;
if (namespace.name) throw new Error (' module "' +name+ '" is already defined ');
Namespace.Name = NAME;
if (version) namespace. Version = version;
Module.modules[name] = namespace;
return namespace;
};
Check name is defined or not
module.isdefined = function (name) {
return name in Module.modules;
};
Check version
Module.require = function (name, version) {
if (!) ( Name in Module.modules)) throw the new Error (' Module ' +name+ ' is not defined ');
if (!version) return;
var n = module.modules[name];
if (!n.version | | n.version < VERSION) throw new Error (' VERSION ' +version+ ' or greater is required ');
};
Import Module
Module.importsymbols = function (from) {
if (typeof form = = ' string ') from = Module.modules[from];
var to = Module.globalnamespace; Dafault
var symbols = [];
var firstsymbol = 1;
if (arguments.length>1 && typeof arguments[1] = = ' object ' && arguments[1]!= null) {
to = arguments[1];
Firstsymbol = 2;
}
for (var A=firstsymbol; a<arguments.length; a++) {
Symbols.push (Arguments[a]);
}
if (Symbols.length = = 0) {
Default Export List
if (from. EXPORT) {
for (var i=0; I<from. Export.length; i++) {
var s = from. Export[i];
To[s] = From[s];
}
Return
else if (!from. EXPORT_OK) {
EXPORT array && export_ok array both undefined
for (Var S. from) {
To[s] = From[s];
Return
}
}
}
if (Symbols.length > 0) {
var allowed;
if (from. EXPORT | | Form. EXPORT_OK) {
allowed = {};
if (from. EXPORT) {
for (var i=0; i<form. Export.length; i++) {
Allowed[from. Export[i]] = true;
}
}
if (from. EXPORT_OK) {
for (var i=0; i<form. Export_ok.length; i++) {
Allowed[form. Export_ok[i]] = true;
}
}
}
}
Import the symbols
for (var i=0; i<symbols.length; i++) {
var s = symbols[i];
if (!) ( s in from) throw new Error (' symbol ' +s+ ' isn't defined ');
if (!! Allowed &&! (s in allowed)) throw new Error (s+ ' isn't public, cannot be imported ');
To[s] = Form[s];
}
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.