Modular programming is a very common form of JavaScript programming. It generally makes the code easier to understand, but there are many good practices that are not widely known. In this article, I will review the basics of JS modular programming and will talk about some of the more advanced topics that are really worth mentioning, including a model that I think is my own creation.
Basis
Let's start with a brief overview of some of the modular models that have been published by Eric Miraglia (the Yui developer) for the first time since the blog described the modular model three years ago. If you are already familiar with these modular patterns, you can skip this section directly and start reading from "Advanced Mode".
Anonymous closures
This is the basic structure that makes everything possible, and it's also the best feature of JavaScript. We will simply create an anonymous function and execute it immediately. All the code will run within this function, surviving in a private closure that is sufficient to allow the variables in these closures to penetrate the entire lifecycle of our application.
(function () {
-VARs and functions are in this scope only
Still maintains access to all globals
}());
Note that the outermost bracket of the enclosing anonymous function is wrapped. This pair of parentheses is necessary because of the language characteristics of JavaScript. A statement that starts with a keyword function in JS is always considered a function declaration. Wrapping this code in parentheses lets the interpreter know that it is a function expression.
Global variable Import
JavaScript has an attribute called an implicit global variable. Regardless of where a variable name is used, the interpreter reverses the Var declaration statement of the variable according to the scope chain. If the Var declaration statement is not found, the variable is treated as a global variable. If the variable is used in an assignment statement, and the variable does not exist, a global variable is created. This means that it is easy to use or create a global variable in an anonymous closure. Unfortunately, this can cause the code written to be extremely difficult to maintain, because for a person's intuitive feelings, it's hard to tell the variables that are global.
Fortunately, our anonymous function provides a simple workaround. As long as you pass global variables to our anonymous functions as arguments, you can get more clear and fast code than implicit global variables. Here is an example:
(Function ($, YAHOO) {
Now have access to Globals JQuery (as $) and YAHOO into this code
} (JQuery, YAHOO));
Module Export
Sometimes you not only want to use global variables, you also want to declare them for reuse. We can easily do this by exporting them--through the return value of the anonymous function. This will complete the prototype of a basic modular paradigm, followed by a complete example:
var MODULE = (function () {
var my = {},
privatevariable = 1;
function Privatemethod () {
// ...
}
My.moduleproperty = 1;
My.modulemethod = function () {
// ...
};
return to my;
}());
Note that we have declared a global module called module, which has 2 public properties: A method called Module.modulemethod and a variable called Module.moduleproperty. In addition, it maintains a private, built-in state that utilizes the closure of anonymous functions. At the same time, we can easily import the required global variables and use this modular pattern as we have learned before.
Advanced Mode
The basics described in the previous section are sufficient to handle many situations, and now we can further develop this modular pattern to create more powerful, scalable structures. Let's start with module modules to introduce these advanced patterns.
Magnification mode
The entire module must be a limitation of the modular pattern in one file. Anyone involved in a large project will understand the value of splitting JS into multiple files. Luckily, we have a great implementation to zoom in on the module. First, we import a module, add attributes to it, and export it at the end. Here's an example--magnify it from the original module:
var MODULE = (function (my) {
My.anothermethod = function () {
Added method ...
};
return to my;
} (MODULE));
We use the VAR keyword to ensure consistency, although it is not required here. After this code has been executed, our module already has a new public method called Module.anothermethod. This enlarged file also maintains its own private built-in state and imported objects.
Wide magnification mode
Our example above requires that our initialization module be executed first, and then the module can be enlarged to perform, although this may not necessarily be necessary at times. One of the best things that JavaScript apps can do to improve performance is to execute scripts asynchronously. We can create flexible, modular modules and allow them to be loaded in any order in a wide magnification mode. Each file needs to be organized according to the following structure:
var MODULE = (function (my) {
Add Capabilities ...
return to my;
} (MODULE {}));
In this pattern, the var expression makes the required. Note This import statement creates a module if the module has not been initialized. This means that you can use a tool like LABJS to load all your module files in parallel without being blocked.
Compact Amplification Mode
The wide magnification mode is great, but it also gives you some limitations on your module. Most importantly, you cannot safely overwrite the properties of the module. You also cannot use attributes from other files when initializing (but you can do this at run time). The compact magnification mode contains a sequence of loaded sequences and allows overriding of attributes. Here is a simple example (enlarge our original module):
var MODULE = (function (my) {
var old_modulemethod = My.modulemethod;
My.modulemethod = function () {
Method Override, has the access to the old through Old_modulemethod ...
};
return to my;
} (MODULE));
We covered the Module.modulemethod implementation in the example above, but we can maintain a reference to the original method when it is needed.
Cloning and inheritance
var Module_two = (function (old) {
var my = {},
Key
For (key in old) {
if (Old.hasownproperty (key)) {
My[key] = Old[key];
}
}
var super_modulemethod = Old.modulemethod;
My.modulemethod = function () {
Override method on the clone, access to super through Super_modulemethod
};
return to my;
} (MODULE));
This model may be one of the most inflexible options. It does make the code look neat, but that's in exchange for the price of flexibility. As I have written above, if an attribute is an object or function, it will not be copied, but will become the second reference to the object or function. Modifying one of these will change the other at the same time: because they are just one! )。 This can be solved by the recursive cloning process, but the cloning of the function may not be resolved, perhaps with eval can be solved. So the way I'm talking about this in this article is simply to take into account the integrity of the article.
Cross File Private variable
There is a significant limitation in the division of a module into multiple files: Each file maintains its own private variables and cannot access private variables to other files. But this problem can be solved. Here is an example of a wide magnification module that maintains a cross file private variable:
var MODULE = (function (my) {
var _private = My._private = my._private {},
_seal = My._seal = My._seal function () {
Delete my._private;
Delete my._seal;
Delete my._unseal;
},
_unseal = My._unseal = My._unseal function () {
My._private = _private;
My._seal = _seal;
My._unseal = _unseal;
};
Permanent access to _private, _seal, and _unseal
return to my;
} (MODULE {}));
All files can set properties on their respective _private variables, and it understands that they can be accessed by other files. Once this module is loaded, the application can invoke Module._seal () to prevent external calls to the internal _private. If this module needs to be magnified, the internal method in any one file can call _unseal () before loading the new file and call _seal () again after the new file has been executed. I now use this pattern in my work, and I have not seen this approach anywhere else. I think this is a very useful model and it is worth writing an article on the pattern itself.
Sub Modules
Our last advanced model is obviously the simplest. There are many good examples of creating child modules. This is like creating a generic module:
Module.sub = (function () {
var my = {};
// ...
return to my;
}());
Although this may seem simple, I think it is worth mentioning here. Sub-modules have all the advanced advantages of general modules, including magnification mode and privatization status.
Conclusion
Most advanced patterns can be combined to create a more useful pattern. If I really wanted to recommend a modular pattern for designing complex applications, I would choose to combine the wide magnification mode, the private variable, and the sub module.
I haven't considered the performance of these patterns yet, but I'd rather turn this into a simpler way of thinking: if a modular model has good performance, it can do a great job of minimizing it, making downloading the script file faster. Using the wide magnification mode allows for simple non-blocking parallel downloads, which speeds up downloads. The initialization time may be slightly slower than other methods, but it is worthwhile to weigh the pros and cons. As long as the global variable is imported accurately, run-time performance should not be affected, and it is possible to get faster speed in the child module by shortening the reference chain with private variables.
As an end, here is an example of a child module dynamically loading itself into its parent module (if the parent module does not exist, it is created). In order to be concise, I have removed the private variables, and of course the private variables are also very simple. This programming pattern allows an entire complex hierarchy of code libraries to be loaded in parallel through a child module.
var UTIL = (function (parent, $) {
var my = Parent.ajax = Parent.ajax {};
My.get = function (URL, params, callback) {
OK, so I ' m cheating a bit:)
Return $.getjson (URL, params, callback);
};
Etc ...
return to parent;
} (UTIL {}, jQuery));
I hope this article is helpful to you, please leave a message below the article to share your idea. From now on, start writing better, more modular JavaScript!