Objective:
Now the JavaScript library is very many, its writing all sorts, summarizes several we often see, as own knowledge accumulation. The current version of JavaScript does not provide a native, language-level modular organizational model, but rather a modular approach for developers. As a result, there are many ways to implement JavaScript modularity,
In AMD, for example, the specification uses the Define function to define a module.
define (Factory () { // Modular });
Module mode:
Module mode uses a feature of JavaScript, the closure (Closures). Some of today's popular JS libraries often see the following forms of code:
;(function (parameter) { // module code // return something;}) (parameters);
The above code defines an anonymous function and immediately calls itself.
Some developers also precede the function expression with an exclamation point (!) or a semicolon (;), instead of enclosing it in parentheses.
! function (parameter) { // code // return something} (parameter);
Others like to enclose the whole iife in parentheses, which becomes the following form:
(function (parameter) { // code // return something} (parameters));
Parameter input:
JavaScript has an attribute called an implicit global variable (implied globals), and when a variable name is used, the JavaScript interpreter iterates through the scope chain to find the declaration of the variable, assuming that the variable is a global variable if it is not found. This feature allows us to refer to global variables, such as jQuery or window, anywhere in the closure. However, this is a bad way.
Considering the module's independence and encapsulation, references to other objects should be introduced through parameters. If other global objects are needed within the module, they should be explicitly referenced as parameters rather than directly referencing the names of those objects within the module. In the case of jquery, it is possible to make an error if the object is referenced directly within the module without entering the jquery object in the parameter. The right way should be roughly like this:
;(function ($, W) { // $ is jQuery // w is window // local variables and codes // return }) (JQuery, window);
Module output (Modules export)
Sometimes we don't just want to use global variables, we also declare and output the objects in the module, which can be achieved by the return statement of the anonymous function, which also forms a complete module pattern.
var klm= (function () { var myklm = {}, modeval = 1 function Privatemethod () { // ... Myklm.moduleproperty = 1 = function () {// ... }; return MYKLM;} ());
This code declares a variable MODULE with two accessible properties: Moduleproperty and Modulemethod, and the rest of the code is encapsulated in a closed package that remains private. Referring to the previously mentioned parameter inputs, we can also refer to other global variables by parameters.
To output a Simple object:
It is common to use object direct amounts to express JavaScript objects. For example: var x = {p1:1, p2: "2", f:function () {/* ... */}}
varModule1 = (function () { varprivate_variable = 1; functionPrivate_method () {/*...*/ } varmy ={property1:1, Property2:private_variable, Method1:private_method, Method2:function () { // ... } }; returnmy;} ());
Output function:
Sometimes what we want to return is not an object, but a function. There are two requirements that require us to return a function, in which case we need it to be a function, such as JQuery, which is a function rather than a simple object, and the other is that we need a "class" instead of a direct amount, and then we can use "new" to instantiate it. The current version of JavaScript does not have a special "class" definition, but it can be expressed by function.
var klm= (function () { // Private members and code ... return function this . Name = name; function () {/* ... */ var com = new KLM ("Quine sensitive"
As mentioned earlier, one form is the direct amount of the Output object (object Literal Notation), and revealing Module pattern is actually this form, just a few limitations. This pattern requires defining variables and functions within the private scope, and then returning an anonymous object in which to specify the members to expose.
var klm= ( function () { // private variable and function var x = 1; function F1 () {} function F2 () {} return { public_method1:f1, public_method2:f2 };} ());
Extension: Tight coupling extension:
Sometimes we ask to invoke methods that have been previously defined in the extension, which can also be used to overwrite existing methods. In this case, the order of definition of the module is required.
var klm = (function (my) { var old_modulemethod = my.modulemethod; function () { // method overloads // can call previous methods via Old_modulemethod ... }; return my;} (KLM));
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));
The above code is streamlined: you can use Object.create ()
var Module_two = (function (old) { var my = object.create (old); var super_modulemethod = old.modulemethod; function () { // override method ... }; return my;} (MODULE));
Adaptation to other module specifications or JS libraries: module Environment Detection:
Today, CommonJS Modules and AMD have a wide range of applications, and if it is determined that AMD's define is available, we can of course use define to write modular code. However, we cannot assume that our code will necessarily run in an AMD environment, is there any way to get our code?
In fact, we just need to add the CommonJS Modules and AMD in a certain place and "register" themselves based on the results of the probe, which are still useful. AMD defines the Define function, and we can use TypeOf to detect whether the function is defined. To be more rigorous, you can continue to determine whether DEFINE.AMD has a definition. In addition, SEAJS also uses the Define function, but not the same as AMD's define. For CommonJS, you can check whether exports or module.exports are defined.
var KLM = (function () { var my = {}; // code ... if (typeof define = = ' function ' Span style= "color: #0000ff;" >function () {return my;}); else if ( typeof module! = ' undefined ' && = my; return my;} ());
Some other JS library practices
How jquery is detected
if(typeofmodule = = = "Object" && module &&typeofModule.exports = = = "Object") {Module.exports=JQuery;} Else { if(typeofdefine = = = "function" &&define.amd) {define ("jquery", [],function() {returnJQuery;} ); }} if(typeofwindow = = = "Object" &&typeofWindow.document = = = "Object") {Window.jquery= window.$ =jQuery;}
Next look at the practice of multiple anonymous functions:
(function(root, factory) {if(typeofExports = = = "Object" &&exports) {Factory (exports);//CommonJS}Else { varMustache = {}; Factory (mustache); if(typeofdefine = = = "function" &&define.amd) {define (mustache);//AMD}Else{root. Mustache= Mustache;//<script> } }}( This,function(mustache) {//The main code of the module is put here.});
This code is not the same as the one described earlier, it uses two anonymous functions. The latter function can be thought of as the factory function of the module code, which is the main part of the module. The previous function detects the running environment and invokes the factory function of the module based on the result of the detection. In addition, as a common library, it does not use the Window object, but instead uses this, because in a simple function call, this is actually a global object.
And look at DoT's approach.
(function() { "Use Strict"; varDoT ={version:' 1.0.0 ', templatesettings: {/*...*/}, template:undefined,//FN, compile templatecompile:undefined//FN, for Express }; if(typeofModule!== ' undefined ' &&module.exports) {module.exports=DoT; } Else if(typeofdefine = = = ' function ' &&define.amd) {define (function(){returnDoT;}); } Else { (function(){return This|| (0,eval) (' this '); } ()). DoT =DoT; } // ...}());
This code (0, eval) (' This ') is a little trick, the expression used to get the global object, ' this ' is actually passed to the eval parameter, but since Eval is obtained indirectly through the expression (0, eval), Eval will be in the global This is found in the object scope, resulting in a global object. If the code is running in a browser, then the Window object is actually obtained.
The future of JavaScript in a modular format
ES 6, which is still in development, defines the language level of the module. Let's take a look at an example, and the following snippet is excerpted from "a couple of new things in Es6:javascript."
module Car { // internal variable var licenseplateno = ' 556-343 '; // exposed to external variables and functions function Drive (speed, direction) { Console.log (' details: ', speed, direction); } Export Module engine{ function check () {} } var miles = 5000 ; var color = ' silver ';};
In the future when I write the JS package above is my reference material, continue the passion of the forward ...
JS Library notation