In this article, I will review the basics of JS modular programming, and will talk about some really noteworthy advanced topics, including a pattern I think I have created myself.
Modular programming is one of the most common JavaScript programming patterns. It can generally make the code easier to understand, but there are many good practices that are not well known.
Basis
Let's start with a brief overview of some of the modular patterns that have been made since Eric Miraglia (the developer of Yui) for the first time since three years ago to describe the modular model. If you are already familiar with these modular modes, you can skip this section and start reading from "Advanced Mode".
Anonymous closures
It's a 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 inside this function, living in a closed package that provides privatization, enough to make the variables in these closures run through the entire lifecycle of our application.
(function () { // ... all vars and Functionsis in this scope only // still maintains accessto all Globals} ());
Note the outermost parentheses of the anonymous function for the package. 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 functional declaration. Wrapping this piece of code in parentheses allows the interpreter to 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 will find the Var declaration statement for the variable based on the scope chain. If the Var declaration statement is not found, then 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 global variables in an anonymous closure. Unfortunately, this can cause the code to be written to be extremely difficult to maintain, because for a person's intuitive perception, it is not clear that the variables are global.
Fortunately, our anonymous function provides a simple workaround. As long as the global variable is passed as a parameter to our anonymous function, we can get a clearer and faster code than the implicit global variable. Here's an example:
(function ($, yahoo) { // now has access to Globals JQuery (as $) and YAHOO. This CO De} (JQuery, YAHOO));
Module Export
Sometimes you want to not only use global variables, you also want to declare them for reuse. We can easily export them to do this-through the return value of the anonymous function. Doing so will complete a basic prototype of modular mode, followed by a complete example:
var MODULE = (function () { var my = {}, privatevariable
= 1; function Privatemethod () { // ... My.moduleproperty = 1 = function () { // ... }; return 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 takes advantage of anonymous function closures. 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 basis described in the previous section is sufficient to deal with many situations, and now we can further develop this modular model to create more powerful, extensible structures. Let's start with module modules and introduce these advanced modes.
Magnification mode
The entire module must be a limitation of the modular mode in one file. Anyone involved in a large project will understand the value of splitting JS into multiple files. Fortunately, we have a great implementation to zoom in on the module. First, we import a module, add properties to it, and finally export it. Here's an example--magnify it from the original module:
var MODULE = (function (my) { function () { // added method ... }; return my;} (MODULE));
We use the VAR keyword to ensure consistency, although it is not required here. After the execution of this code, our module already has a new public method called Module.anothermethod. This zoomed-in file also maintains its own private built-in state and imported objects.
Wide magnification mode
Our above example requires that our initialization module be executed first, then the module can be scaled to execute, and sometimes this may not necessarily be necessary. One of the best things a JavaScript app can do to improve performance is to execute scripts asynchronously. We can create flexible multipart modules and enable them to be loaded in any order by using the wide magnification mode . Each file needs to be organized according to the following structure:
var MODULE = (function (my) { // add capabilities ... return || {}));
In this pattern, the var expression makes the required. Note If the module has not been initialized, the import statement creates a module. This means that you can use a tool like LABJS to load all of your module files in parallel without being blocked.
Compact magnification mode
The wide magnification mode is great, but it also brings some limitations to your module. Most importantly, you cannot safely override the properties of a module. You also can't use attributes from other files while initializing (but you can use them at run time). The compact magnification mode contains a sequential sequence of loads and allows overriding properties . Here is a simple example (enlarge our original module):
var MODULE = (function (my) { var old_modulemethod = my.modulemethod; function () { // method Override, have access to old through Old_modulemethod ... }; return my;} (MODULE));
We covered the implementation of Module.modulemethod in the example above, but when needed, we can maintain a reference to the original method.
Cloning and inheritance
varModule_two = (function(old) {varmy ={}, key; for(KeyinchOld ) { if(Old.hasownproperty (key)) {My[key]=Old[key]; } } varSuper_modulemethod =Old.modulemethod; My.modulemethod=function () { //override method on the clone, access to super through Super_modulemethod }; returnmy;} (MODULE));
This pattern is probably one of the most inflexible options. It does make the code look neat, but it's the price of flexibility. As I wrote above, if a property is an object or function, it will not be copied, but will become a second reference to the object or function. Modifying one of these changes the other at the same time (translator Note: Because they are all one!) )。 This can be done through the recursive cloning process to solve this object cloning problem, but the function cloning may not be solved, perhaps with eval can solve it. Therefore, I have described this approach in this article only to take into account the integrity of the article.
Cross-file private variables
There is a significant limitation in splitting a module into multiple files: Each file maintains its own private variables and cannot access the private variables of other files. But this problem can be solved. Here is an example of a wide magnification module that maintains a cross-file private variable:
varMODULE = (function(my) {var_private = My._private = My._private | |{}, _seal= My._seal = My._seal | |function () { Deletemy._private; DeleteMy._seal; DeleteMy._unseal; }, _unseal= My._unseal = My._unseal | |function() {my._private=_private; My._seal=_seal; My._unseal=_unseal; }; //permanent access to _private, _seal, and _unseal returnmy;} (MODULE|| {}));
All files can have properties set on their respective _private variables, and it understands that they can be accessed by other files. Once the module is loaded, the application can call Module._seal () to prevent external calls to the internal _private. If the module needs to be magnified, the internal method in any file can call _unseal () before loading the new file and call _seal () again after the new file is executed. I use this pattern at work now, and I haven't seen it anywhere else. I think it's a very useful model and it's worth writing an article about the pattern itself.
Module.sub = (function () { var my = {}; // ... return my;} ());
Although this may seem simple, I think it is worth mentioning here. Sub-modules have the advanced advantages of all general modules, including amplification mode and privatization status.
Conclusion
Most advanced modes can be combined to create a more useful pattern. If I were to recommend a modular pattern for designing complex applications, I would choose to combine wide magnification, private variables, and sub-modules.
I haven't considered the performance issues 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 it faster to download the script file. Using the wide magnification mode allows for simple non-blocking parallel downloads, which speeds up the download speed. The initialization time may be slightly slower than other methods, but it is worthwhile to weigh the pros and cons. As long as global variables are imported accurately, run-time performance should not be affected, and it may be possible to run faster by shortening the reference chain with private variables in the submodule.
As an end, here is an example of a submodule dynamically loading itself into its parent module (creating it if the parent module does not exist). For brevity, I have removed the private variables, and of course the private variables are very simple. This programming pattern allows a whole complex hierarchy of code libraries to be loaded in parallel through a submodule.
var UTIL = (function (parent, $) { var my = Parent.ajax = Parent.ajax | | {}; function (URL, params, callback) { // OK, so I ' m cheating a bit:) return $.getjson (URL, params, callback); }; // etc... return || {}, jQuery));
This article summarizes the current "JavaScript modular Programming" best practices and shows how to put it into practice. Although this is not a beginner tutorial, you can understand the basic syntax of JavaScript a little bit.
JavaScript Modular Programming detailed