"Component Mode" is a common Javascript encoding mode. Although it has been widely used, there are still some advanced functions that have not been concerned. In this article, I will briefly elaborate on several special topics, some of which I think should be mentioned for the first time.
Basic
Starting from a simple component model, this model is now very popular. It was initially proposed by Eric Miraglia of Yahoo YUI three years ago in his blog. If you are familiar with this mode, you can directly jump to the "advanced mode" section.
Anonymous closure (Anonymous Closures)
This is the language basis for making the mode work normally. It is also one of the most practical features of javascript. We can simply create an anonymous function and execute it immediately. All the code running in this function is called a closure, which provides effective data privacy control and state saving throughout the application lifecycle.
- (function () {
- // ... all vars and functions are in this scope only
- // still maintains access to all globals
- }());
Note that () is surrounded by anonymous functions. This is a syntax requirement, because statements starting with a function will be defined by functions recognized by the compiler, and () to create a function expression.
Global Import)
JavaScript has a well-known feature called implied globals, that is, when a variable is used, the interpreter will always look up the definition of this variable along the scope chain, if not found, this variable will automatically become a global variable. This means it is very easy to create a global variable in an anonymous closure.
However, this produces code problems that are difficult to manage, because we cannot clearly know which variables in a given file are global.
(Note: If you allow this obscure method to create global variables, it is hard to know whether the variables used in the Code are global or local .)
Fortunately, our anonymous function provides a simple modification to solve this problem. We pass in a global object as the parameter of the anonymous function. We use this parameter to import our variables to the global object, which is much cleaner and faster than the implicit declaration of global variables. The following is an example.
- (function ($, YAHOO) {
- // now have access to globals jQuery (as $) and YAHOO in this code
- }(jQuery, YAHOO));
Module Export)
Sometimes we don't just want to define a module, but also want to use it directly. We can use the return values of anonymous functions. In this case, a basic "component mode" is implemented. See the following example:
- var MODULE = (function () {
- var my = {},privateVariable = 1;
- function privateMethod() {
- // ...
- }
- my.moduleProperty = 1;
- my.moduleMethod = function () {
- // ...
- };
- return my;
- }());
Note that a global component named "MODULE" has two attributes: MODULE. moduleMethod and MODULE. moduleProperty. In addition, it maintains a set of private internal states through the closure of the anonymous function.
(Note: Both the privateVariable variable and the privateMethod method are private and cannot be accessed from outside ).
In this way, we can use the above mode to simply import the required global variables.
Advanced Patterns)
The above model can solve many problems in applications, but we can also expand many powerful and scalable structures on this basis. Let's take a look at them one by one and continue to use our component "MODULE" as an example.
Gain mode (Augmentation)
One of the disadvantages and limitations of using the above mode is that the entire module must be in a file. Anyone working in a large project will realize the value of splitting code into multiple files. Fortunately, we have a good solution called "Gain component ". First, import the component, add the attribute, and then export it. The following is an example to add the gain feature for our MODULE component:
- var MODULE = (function (my) {
- my.anotherMethod = function () {
- // added method...
- };
- return my;
- }(MODULE));
We use the var keyword to maintain consistency (although this is not necessary ). After this code is executed, our component adds a public method called MODULE. anotherMethod. The added file also maintains its own private State.
(Translator's note: In gain mode, a ray is split into independent files, and each file focuses on the methods and attributes it needs internally. When all files are merged and executed, can be a complete component)
Loose Augmentation)
One disadvantage of the above example is that the MODULE needs to be created first, and then the gain in the sub-file is executed. This is a tightly coupled approach. The common practice in javascript performance optimization is asynchronous loading of scripts, so that we can create scalable components consisting of multiple files and they can be loaded in any order, this is called the loosely coupled gain mode:
- var MODULE = (function (my) {
- // add capabilities...
- return my;
- }(MODULE || {}));
In this mode, the var keyword is required. Note that our import point (parameter) will automatically determine whether the component exists; otherwise, an empty component will be created. This means that you can use some asynchronous loading tools such as LABjs to load all your js components in parallel without the need to block pages.
Tight Augmentation)
The "loosely coupled gain" mode is great, but it also has some limitations. The most important thing is that attributes cannot be rewritten. You cannot use the content of other files during component initialization (because the loading order cannot be guaranteed). The "tightly coupled gain mode" requires an orderly Loading Order, however, it is a simple example that allows you to override the content of other files:
- var MODULE = (function (my) {
- var old_moduleMethod = my.moduleMethod;
- my.moduleMethod = function () {
- // method override, has access to old through old_moduleMethod...
- };
- return my;
- }(MODULE));
Here we overwrite MODULE. moduleMethod, and save the reference of the old MODULE. moduleMethod method (if 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 my;
- }(MODULE));
This mode may be the least extensible option. Although it seems to make the code more concise, it brings about the loss of scalability. In the code above, all attributes and methods are not copies, and they exist in the form of "two references to an object. Modifying one of them will affect the other.
Cross-File Private State)
Another restriction that separates components into multiple files is that each file can only access its own private State, but has no permission to access the private data of other files. This problem can be solved. The following is a version of the "loosely coupled gain mode" that accesses private States across files:
- 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 my;
- }(MODULE || {}));
Now, any file can set properties in the local Variable _ private, and the setting result is immediately fed back to other files. Once the component is loaded, the application should call the MODULE. _ seal () method, which will prevent the external program from accessing the internal attribute _ private. If this component is extended (GAIN) by other files, you can call the _ unseal () method to unseal the component before loading the new file, after the file is loaded, call _ seal () to shield the class from the outside again.
Note: The _ unseal method adds one public attribute and two public methods to the object. Other files can be expanded in the private attribute of my object squadron, then, the public attributes are deleted using the _ seal () method to keep the object confidential)
This mode was created when I was working today. I have never seen it in other places. I think it is a very useful mode.
Sub-modules)
Our final advanced pattern is actually the simplest. There are too good cases for creating sub-modules. It is just like creating regular modules:
The last advanced mode is actually the simplest. There are many benefits for creating submodules. Creating submodules is the same as creating common modules:
- MODULE.sub = (function () {
- var my = {};
- // ...
- return my;
- }());
Although this is simple, I still think that sub-modules should be included, because sub-modules have all the advanced features of normal modules, including gain and private data storage.
Conclusion
Most advanced modes can be used in combination. For me, I prefer to combine "loosely coupled gain", "Private state storage", and "sub-mode ".
I did not discuss performance-related content in this article, but I would like to briefly describe that the component mode is good for performance. Because it does make the download much faster: the "loosely coupled gain" mode allows the script to load without blocking in parallel, which speeds up the download. The overall initialization completion time may be slower than other methods, but this is worthwhile.
At the end, there is an example of a sub-module that dynamically loads itself into its parent module. This mode allows the entire module to load itself and its sub-modules in parallel.
From: The blog of the assassin's house