I have always had little knowledge of JS. I encountered this problem recently, so I studied it online. I still don’t fully understand it, so I will post my notes first;
Chapter 1 JavaScript Modular Programming
(1): How to write modules
1 Original writing
// A module is a set of methods to implement a specific function; as long as different functions (and variables that record status) are simply put together, it is a module;
Function m1(){
// ...
}
Function m2(){
// ...
}
// The above functions m1() and m2() form a module; just call it directly when using it;
// Disadvantages: "Polluted" global variables; there is no guarantee that variable names will not conflict with other modules, and there is no direct relationship between module members;
2 Object Writing Method
// 把模块写成一个对象,所有的模块成员都放到这个对象里面; var module = new Object({ _count:0, m1:function(){ // ... }, m2:function(){ // ... } }); // 上面的函数m1()和m2(),都封装在module对象里;使用时直接调用这个对象的属性; module.m1(); // 但是,这样的写法会暴露所有模块成员,内部状态可以被外部改写; module._count = 4;
3 How to write immediate execution function
var module = (function(){ var _count = 0; var m1 = function(){ // ... }; var m2 = function(){ }; return { m1:m1, m2:m2 }; })(); // 使用上面的写法,外部代码无法读取内部的_count变量; console.info(module._count); // undefined; // 上面的写法就是JavaScript模块的基本写法;
Four zoom modes
// 如果模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"; var module = (function(mod){ mod.m3 = function(){ // ... }; return mod; })(module); // 上面的代码为module模块添加了一个新方法m3(),然后返回新的module模块;
5 Wide zoom mode
// 在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载; // 如果采用上一节的写法,第一个执行的部分有可能加载一个不存在的空对象,这时就要采用"宽放大模式"; var module = (function(mod){ // ... return mod; })(window.module || {}); // 与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象;
6 Enter global variables
// 独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互; // 为了在模块内部调用全局变量,必须显式地将其他变量输入模块; var module = (function($,YAHOO){ // ... })(jQuery,YAHOO); // 上面的module模块需要使用jQuery库和YUI库,就把这两个库(其实是两个模块)当作参数输入module; // 这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显;
Chapter 2 JavaScript Modular Programming (2): AMD Specification
1 Module Specifications
// Currently, there are two popular JavaScript module specifications: CommonJS and AMD;
2 CommonJS
// node.js uses JavaScript language for server-side programming, which marks the official birth of "JavaScript modular programming";
// The module system of node.js is implemented with reference to the CommonJS specification;
In CommonJS, there is a global method require() for loading modules;
var math = require('math'); var math = require('math'); // Load module;
Math.add(2,3); // Call module method =>5;
3 Browser environment
// The code in the previous section will have big problems when running in the browser;
var math = require('math');
Math.add(2,3);
// Problem: You must wait for math.js to be loaded in require('math') before math.add(2,3);
// Therefore, browser modules cannot use "synchronous loading" and can only use "asynchronous loading";==>AMD;
Four AMD
AMD (Asynchronous Module Definition) asynchronous module definition;
// Use asynchronous loading of modules. The loading of the module does not affect the execution of subsequent statements. All statements that depend on this module are defined in a callback function,
// This callback function will not run until loading is complete;
// AMD also uses the require() statement to load modules, but it requires two parameters:
require([module],callback);
// module: is an array, the members inside are the modules to be loaded;
// callback: is the callback function after successful loading;
require(['math'],function(math){
Math.add(2,3);
});
// math.add() and math module loading are not synchronized, and the browser will not freeze; therefore, AMD is more suitable for the browser environment;
Chapter 3 JavaScript Modular Programming (3): Usage of require.js
1. Why use require.js
// Multiple js files need to be loaded in sequence;
// Disadvantages:
// 1. When loading, the browser will stop rendering the web page. The more files loaded, the longer the web page will lose response;
// 2. Due to the dependencies between js files, the loading order must be strictly guaranteed. When the dependencies are complex, code writing and maintenance will become difficult;
// So require.js solves these two problems:
// 1. Implement asynchronous loading of js files to avoid web pages losing response;
// 2. Manage dependencies between modules to facilitate code writing and maintenance;
2 Loading of require.js
1. Load require.js
// The async attribute indicates that this file needs to be loaded asynchronously to prevent the web page from losing response; IE does not support this attribute, only defer, so write defer as well;
2. Load main.js
// The function of the data-main attribute is to specify the main module of the web program => main.js. This file will be the first to be loaded by require.js;
// Since the default file suffix of require.js is js, main.js can be abbreviated as main;
3 How to write the main module main.js
1. If main.js does not depend on any other modules, JavaScript code can be written directly;
// main.js
alert('Loading successful!');
2. If main.js depends on the module, you must use the require() function defined by the AMD specification;
// main.js
require(['moduleA','moduleB','moduleC'],function(moduleA,moduleB,moduleC){
// ...
})
// require() function receives two parameters:
// Parameter 1: Array, indicating the modules it depends on, that is, the three modules that the main module depends on;
//Parameter two: callback function, which will be called after all the previously specified modules are loaded successfully; the loaded modules will be passed into the function as parameters, so that these modules can be used inside the callback function;
// require() loads modules asynchronously, and the browser will not lose response; the callback function it specifies will only run after the previous modules are loaded successfully, solving the dependency problem;
Example:
require(['jquery','underscore','backbone'],function($,_,Backbone){
// ...
});
Four module loading
//Use the require.config() method to customize the loading behavior of the module;
// require.config() is written at the head of the main module (main.js);
// The parameter is an object, and the paths attribute of this object specifies the loading path of each module;
// Set the files of the following three modules to use the same directory as main.js by default;
require.config({
paths:{
"jquery":"jquery.min",
"underscore":"underscore.min",
"backbone":"backbone.min"
}
});
// If the loaded module and the main module are not in the same directory, you must specify the paths one by one;
require.config({
paths:{
"jquery":"lib/jquery.min",
"underscore":"lib/underscore.min",
"backbone":"lib/backbone.min"
}
});
// Or directly change the base directory (baseUrl)
require.config({
baseUrl:"js/lib",
paths:{
"jquery":"jquery.min",
"underscore":"underscore.min",
"backbone":"backbone.min"
}
});
// If the module is on another host, you can also specify its URL directly
require.config({
paths:{
"jquery":"https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
}
});
// require.js requires that each module is a separate js file; in this case, if multiple modules are loaded, multiple HTTP requests will be issued, which will affect the loading speed of the web page;
// Therefore, require.js provides an optimization tool. After the module is deployed, you can use this tool to merge multiple modules into one file to reduce the number of HTTP requests;
How to write five AMD modules
// The modules loaded by require.js adopt AMD specifications, that is to say, the modules must be written in accordance with AMD regulations;
// Specifically, the module must be defined using a specific define() function; if a module does not depend on other modules, it can be defined directly in the define() function;
// Define math module in math.js
// math.js
define(function(){
var add = function(x,y){
return x y;
};
return {
add:add
};
});
//Load the math module in main.js
require(['math'],function(math){
alert(math.add(1,1));
});
// If this module also depends on other modules, then the first parameter of the define() function must be an array to indicate the dependencies of the module;
// math.js
define(['myLib'],function(myLib){
function foo(){
myLib.doSomething();
}
return {
foo:foo
};
});
// When the require() function loads the above module, the myLib.js file will be loaded first;
6 Loading non-standard modules
// To load non-standard modules, before loading them with require(), you must first use the require.config() method to define some of their characteristics;
require.config({
shim:{
'underscore':{
exports:'_'
},
'backbone':{
deps:['underscore','jquery'],
exports:'Backbone'
}
}
});
// require.config() receives a configuration object. In addition to the paths attribute mentioned earlier, this object also has a shim attribute, which is specially used to configure incompatible modules;
// (1). Define the deps array to indicate the dependencies of the module;
// (2). Define the exports value (output variable name), indicating the name of this module when called externally;
For example: jQuery plug-in
shim:{
'jquery.scroll':{
deps:['jquery'],
Exports:'jQuery.fn.scroll'
}
};
Seven require.js plug-ins
1.domready: The callback function can be run after the page DOM structure is loaded;
require(['domready!'],function(doc){
// called once the DOM is ready;
})
2.text and image: Allow require.js to load text and image files;
Define(['text!review.txt','image!cat.jpg'],function(review,cat){
console.log(review);
document.body.appendChild(cat);
});