In the early development of JavaScript is to achieve simple page interaction logic, just a few words; Nowadays, CPU and browser performance have been greatly improved, and a lot of page logic has been migrated to the client side (form verification, etc.). With the advent of Web2.0 era, Ajax technology has been widely used, jQuery and other front-end libraries emerge in endlessly, and front-end code is expanding day by day. At this point, JavaScript’s position as an embedded scripting language is shaken, but JavaScript offers no obvious help in organizing code, not even the concept of classes, let alone modules. JavaScript’s extremely simple code organization specification is not enough to handle such a large scale of code.

The module

Since JavaScript cannot handle such a large amount of code, we can learn how other languages handle large-scale programming. In Java, there is an important concept called package. Logically related code is organized into the same package, which is a relatively independent kingdom. Don’t worry about naming conflicts or anything, but what about external use? Import java.util.ArrayList; import java.util. Unfortunately, JavaScript was designed for reasons other than providing similar functionality, and developers need to simulate similar functionality to isolate and organize complex JavaScript code, which we call modularity. A module is a file that implements a particular function. With a module, we can more easily use other people’s code and load whatever function we want. Module development needs to follow a certain set of rules, and everything goes wrong. The process of the formation of norms is painful. The pioneers of the front end began in the stage of slash-and-burn farming and drinking blood, and developed to take shape now. A brief understanding of this extraordinary process.

One, function encapsulation

When we talked about functions, we mentioned that a function is a package of statements that implement a particular logic, and JavaScript’s scope is based on functions, so it’s a natural first step to modularize functions. Writing several related functions in a file is a starting module, as follows:

 function fn1(){
    statement
}
 
function fn2(){
    statement
} 
Copy the code

In this way, after the need to clip the function in the file, call the function can be. The disadvantages of this approach are obvious: it contaminates global variables, there is no guarantee of variable name conflicts with other modules, and there is little relationship between module members.

Second, objects,

To solve the above problem, object writing method came into being, you can encapsulate all module members in one object, look at the following code:

var myModule = {
 
var1: 1,
 
var2: 2,
 
fn1: function(){
 
},
 
fn2: function() {}}Copy the code

This way we reference the corresponding file whenever we want to invoke the module, and then execute

myModule.fn2();
Copy the code

This avoids variable contamination, as long as the module name is unique and members of the same module are related. This may seem like a good solution, but it has a downside: outsiders can modify internal members at will,

myModel.var1 = 100;
Copy the code

This can create unexpected security problems.

Third, execute the function immediately

You can hide details by executing the function immediately, as shown in the following code,

var myModule = (function(){
 
var var1 = 1;
 
var var2 = 2;
 
function fn1(){
 
}
 
function fn2(){
 
}
 
return{ fn1: fn1, fn2: fn2 }; }) ();Copy the code

In this way, we cannot modify variables and functions that are not exposed outside the module. This is the basis of our modularization. Currently, there are two common JavaScript module specifications: CommonJS and AMD.

CommonJS

We will start with CommonJS, because there is no modular programming on the web side, but JavaScript logic is complicated, but it can work, but there must be modules on the server side, so although JavaScript has been developed on the Web side for so many years, The first popular modularity specification came from server-side JavaScript applications. The CommonJS specification was carried forward by NodeJS, which marked the formal arrival of JavaScript modularity programming. Define modules: According to the CommonJS specification, a single file is a module. Each module is a separate scope, that is, variables defined inside the module cannot be read by other modules unless they are defined as properties of the Global object. Module output: The module has only one export, the module.exports object, into which we need to put what the module wants to export. The module is loaded using the require method, which reads a file and executes, returning the module.exports object inside the file. Here’s an example:

  var name = 'Byron';
 
    function printName(){
 
    console.log(name);
 
    }
 
    function printFullName(firstName){
 
    console.log(firstName + name);
 
    }
 
    module.exports = {
 
    printName: printName,
 
    printFullName: printFullName
 
    }
Copy the code

Then load the module,

var nameModule = require('./myModel.js');
nameModule.printName();
Copy the code

Different implementations require different paths. In general, js extensions can be omitted, relative paths can be used, absolute paths can be used, and even the path can be omitted directly using the module name (provided that the module is a system built-in module).

An embarrassed browser looking closely at the code above will see that require is synchronized. The module system needs to read the contents of the module file synchronously and compile the execution to get the module interface. This is easy and natural to implement on the server side, however, there are many problems to implement on the browser side. On the browser side, the best and easiest way to load JavaScript is to insert script tags in document. But script tags are inherently asynchronous, and traditional CommonJS modules don’t load properly in a browser environment. One solution is to develop a server-side component that statically analyzes the module code and returns the module to the browser side with a list of its dependencies. This works fine, but requires additional components to be installed on the server and a series of underlying architectures to be adjusted as a result. Another solution is to encapsulate module definitions with a standard set of templates, but there are disagreements about how modules should be defined and loaded.

AMD

AMD is an Asynchronous Module Definition. It is a specification for modular development on the browser side. Because it is not JavaScript native support, page development using AMD specification needs corresponding library functions, namely the famous RequireJS. In fact, AMD is the standardized output of RequireJS module definition in the promotion process. RequireJS mainly solves two problems: first, multiple JS files may have dependencies, and the dependent files need to be loaded into the browser before the dependent files; Second, the browser will stop page rendering when JS is loaded. The more files loaded, the longer the page will lose response time. Consider an example using requireJS:

Mymodule.js define(['dependency'].function(){
 
var name = 'Byron';
 
function printName(){
 
console.log(name);
 
}
 
return {
 
printName: printName }; }); // require(['myModule'].function (my){
 
  my.printName();
 
});
Copy the code

grammar

RequireJS defines a function define, which is the global variable used to define the module. define(id? , dependencies? , factory); —— ID: an optional parameter used to define the module id. If this parameter is not provided, the script name is deleted. ——dependencies: is an array of module names that the current module depends on —— Factory: a factory method that a module initializes a function or object to execute. If it is a function, it should be executed only once. If it is an object, the object should be the output value of the module;

Load the module on the page using the require function; require([dependencies], function(){}); The require() function takes two arguments: the first argument is an array representing the dependent module; The second argument is a callback function that will be called after all the modules specified in the previous page have been successfully loaded. Loaded modules are passed to the function as arguments, so they can be used inside the callback function. The require() function is asynchronously loaded when loading dependent functions, so that the browser does not lose response, and it specifies a callback function that will not run until all previous modules have been successfully loaded.

CMD

CMD is the Common Module Definition, CMD specification is developed in China, just as AMD has a requireJS, CMD has a browser implementation SeaJS, SeaJS to solve the same problem as requireJS, The sea-js syntax advocates a module per file, and follows the common syntax define define(ID? , deps? Since CMD advocates per-file/module, it often uses the filename as the module ID; CMD advocates nearby dependencies, so instead of writing dependencies in define parameters, you write them in Factory. Factory takes three arguments: Function (require, exports, module){}} function(require, exports, module){}} function(exports, module){}} function(exports, module){}} Exports exports is an object that provides a module interface. A module is an object that stores properties and methods associated with the current module.

Mymodule.js define(function(require, exports, module) {
  var $ = require('jquery.js'The $()'div').addClass('active'); }); Seajs.use ([)'myModule.js'].function(my){

});
Copy the code

There are dozens of articles on the Internet about the differences between AMD and CMD, which can be summarized briefly: The most obvious difference is that the dependency is treated differently in module definition. AMD advocates dependency predisposition, declaring the module it depends on when defining a module, while CMD advocates nearby dependency, requiring only when a module is used. This difference has its advantages and disadvantages, but there is only a gap in syntax. Both requireJS and SeaJS support each other.

The biggest difference between AMD and CMD is that the execution time of dependent modules is handled differently, not the loading time or the way. It is not correct to say that requireJS and SeaJS load modules asynchronously. In fact, all modules load asynchronously, but AMD relies on the front, js can easily know who the dependent module is, and load immediately, while CMD relies on the nearby module. The need to parse modules into strings to know which modules depend on is also one of the many complaints about CMD, sacrificing performance for ease of development, and in fact the time spent parsing modules is negligible. Why we say that the difference between the two is the dependency module execution timing, and why many people think that ADM is asynchronous and CMD is synchronous (except for the name…). Also are asynchronous loading module, AMD after completion of the loading modules will be executed to change module, all modules loaded after the execution will enter the require of the callback function, implement the main logic, the effect is dependent on module order execution order, and do not necessarily consistent, the network speed, which first download, which performed first, But the main logic must not be executed until all dependencies have been loaded. CMD does not execute a dependent module after loading it, but only downloads it. After loading all dependent modules, enter the master logic and execute the corresponding module when encountering the require statement. In this way, the execution order of modules is exactly the same as the writing order. This is why many people say that AMD has a good user experience because there is no latency, dependencies are executed ahead of time, and CMD performance is good because it is executed only when the user needs it. Articles from https://blog.csdn.net/wsymcxy/article/details/82177475, thanks for bosses