Modular summary

Modular summary

1. Introduction to Modularity

1.1 The concept of modules

  • Encapsulate a complex program into several blocks (files) according to certain rules (standards), and combine them together

  • These split files are modules. The internal data/implementation of the module is private, and it only exposes some interfaces (methods) to communicate with other external modules.

1.2 The composition of the module

(1) Data ---> internal attributes

(2) The behavior of manipulating data ---> internal functions

1.3 The concept of modularity

  • When coding, it is coded one by one according to the modules , and the entire project is a modular project

1.4 Why modularize?

(1) Reduce complexity and improve decoupling

(2) Avoid naming conflicts (reduce namespace pollution)

(3) Better separation, load on demand

(4) Higher reusability and high maintainability

2. Modular evolution history

2.1 Global function mode

  • Global function mode: encapsulate different functions into different global functions

  • Problem : The whole world is polluted, which can easily cause naming conflict

Examples:

//module1.js //data let data = 'atguigu.com' //function to manipulate data function foo () { console .log( `foo() ${data} ` ) } function bar () { console .log( `bar() ${data} ` ) } //module2.js let data2 = 'other data' ; function foo () { //This conflicts with a function in another module console .log( `foo() ${data2} ` ) } //test.html <script type= "text/javascript" src= "module1.js" ></script> < script type = "text/javascript" src = "module2.js" > </script > < script type = "text/javascript" > let data = "I am the modified data" //This conflicts with a variable in a module foo() bar() </script > copy code

2.2 namespace mode-simple object encapsulation

  • namespace mode: simple object encapsulation

  • Role: reduced global variables

  • Problem : Insecure (data is not private, it can be directly modified externally)

Examples:

//module1.js let myModule = { data : 'module1 atguigu.com' , foo () { console .log( `foo() ${ this .data} ` ) }, bar () { console .log( `bar() ${ this .data} ` ) } } //module2.js let myModule2 = { data : 'module2 atguigu.com' , foo () { console .log( `foo() ${ this .data} ` ) }, bar () { console .log( `bar() ${ this .data} ` ) } } //test.html <script type= "text/javascript" src= "module2.js" ></script> < script type = "text/javascript" src = "module22.js" > </script > < script type = "text/javascript" > myModule.foo() myModule.bar() myModule2.foo() myModule2.bar() //The data inside the module can be directly modified externally myModule.data = 'other data' myModule.foo() </script > copy code

2.3 IIFE mode

  • IIFE mode: anonymous function self-calling (may produce closure)

  • IIFE: immediately-invoked function expression (immediately-invoked function expression)

  • Role: The data is private, and the outside can only be manipulated through exposed methods

  • problem : What if the current module depends on another module?

Examples:

//module1.js ( function ( w ) { //data let data = 'atguigu.com' //Function to manipulate data function foo to () { //Exposed internal private functions console .log( `foo() ${data} ` ) } function bar () { //Exposed internal private functions console .log( `bar() ${data} ` ) otherFun() //Internal call } function otherFun () { //Unexposed internal private function console Unexposed .log( 'otherFun()' ) } //Exposure behavior w.myModule = {foo, bar} })( window ) //test.html <script type= "text/javascript" src= "module1.js" ></script> < script type = "text/javascript" > myModule.foo() myModule.bar() //myModule.otherFun()//error: myModule.otherFun is not a function console .log(myModule.data) //undefined cannot access the internal data of the module myModule.data = 'xxxx' //not the internal modification of the module Data myModule.foo () //unaffected </Script > copy the code

2.4 IIFE mode enhancement

  • IIFE mode enhancement: introducing dependency

  • This is the cornerstone of modern modularization

Examples:

//module1.js ( function ( window , $ ) { //data let data = 'atguigu.com' //Function to manipulate data function foo () { //Used to expose the function console .log( `foo() ${data} ` ) $( 'body' ).css( 'background' , 'red' ) } function bar () { //Used to expose the function console .log( `bar() ${data} ` ) otherFun() //Internal call } function otherFun () { //Internal private function console .log( 'otherFun()' ) } //behavior exposure window .myModule = {foo, bar} })( window , jQuery) //test.html //Introduce jquery <script type= "text/javascript" src= "jquery-1.10.1.js" ></script> < script type = "text/javascript" src = "module4.js" > </script > < script type = "text/javascript" > myModule.foo() </script > copy code

3. The problem of page loading multiple js

  • One page needs to introduce multiple js files

  • problem:

    • Too many requests
    • Reliance on ambiguity
    • Difficult to maintain
  • These problems can be solved by modern modular coding and project construction

//Reality < script type = "text/javascript" src = "module1.js" > </script > < script type = "text/javascript" src = "module2.js" > </script > < script type = "text/javascript" src = "module3.js" > </script > < script type = "text/javascript" src = "module4.js" > </ script> <script type = "text/javascript" src = "module5.js" > </script > < script type = "text/javascript" src = "module6.js" > </script > < script type = "text/javascript " src = "module7.js" > </script > < script type = "text/javascript" src = "module8.js" ></script > < script type = "text/javascript" src = "module9.js" > </script > < script type = "text/javascript" src = "module10.js" > </script > < script type = "text/javascript" src = "module11.js" > </script > < script type = "text/javascript" src = "module12.js" ></script > copy code

4. Modular specification

4.1CommonJS --- Two-ended specification (browser/server) (emphasis!)

1. On the server side: the loading of the module is synchronously loaded at runtime

2. On the browser side: the module needs to be compiled and packaged in advance

3. Before modularization, you need to use the npm init command to initialize the project structure

4. Expose the syntax

  1. module.exports = {value}

  2. exports.xxx = value

Note:

  • exports is an alias of module.exports (address reference relationship)

  • In the CommonJs module specification, module.exports and exports.xxx cannot be mixed.

  • If mixed, the export object is mainly module.exports

5. Introduce syntax (used in the summary file app.js)

  • require(xxx)

  • Third-party module: xxx is the name of the module

  • Custom module: xxx is the path of the module file, with ./

Note: The suffix can be omitted when importing the module!

6. What is the nature of exposure?

  • The object pointed to by module.exports

4.1.1 Server side (Node)

//module1.js /* * The first way of exposure: module.exports = value * */ module .exports = { data : 'atguigu' , test () { console .log( this .data) } } //The following line of code will also be executed, but without any exposure console .log( 'nice' ) //module2.js /* * The second way of exposure: exports.xxx = value * */ exports .haha = function () { console .log( 'I am a function in module2' ) } //module3.js /* problem: 1. What is the essence of exposure? The object pointed to by module.exports 2. In the CommonJs module specification, module.exports and exports.xxx cannot be mixed. 3. If mixed, use module.exports as the main */ exports .peiqi = [ 1 , 3 , 5 , 7 , 9 ] module .exports = function haha () { console .log( 'haha' ) } //app.js /* * The main file, used to summarize the various modules * Note: When introducing the module: * 1. If the imported module is a third-party module, write the module name directly. * 2. If the imported module is a custom module, the path must be written, and ./must be added. * */ let module1 = require ( './modules/module1.js' ) let {data,test} = require ( './modules/module1.js' ) //At the same time of introduction, perform deconstruction assignment let module2 = require ( './modules/module2.js' ) let module3 = require ( './modules/module3.js' ) let uniq = require ( 'uniq' ) //How to use a module depends on: what the module exposes. console .log(module1.data); module1.test(); module2.haha(); console .log(module3.peiqi); console .log(uniq([ 1 , 3 , 2 , 5 , 4 , 3 , 6 , 7 , 11 , 10 , 9 , 8 ])); console .log(data) test() console .log( require ( './modules/module1' ).data) //verify the relationship built Console .log ( Module .exports === Exports ) Console .log ( Module .exports) Console .log ( Exports ) Copy the code

4.1.2 Browser

1. The browser side needs to use Browserify to implement the require function

  • Browserify is used to translate the modular syntax of CommonJS into the syntax recognized by the browser, and is a "translator"

  • Install browserify globally: npm install browserify -g

2. In the folder where app.js is located

  • Enter the command browserify js/src/app.js -o js/dist/bundle.js

  • -o means output

  • The name of bundle.js can be changed

Example: The core code is the same as the Node side, except that the html file import module is added.

//module1.js /* * The first way of exposure: module.exports = value * */ module .exports = { data : 'atguigu' , test () { console .log( this .data) } } //The following line of code will also be executed, but without any exposure console .log( 'nice' ) //module2.js /* * The second way of exposure: exports.xxx = value * */ exports .haha = function () { console .log( 'I am a function in module2' ) } //module3.js /* problem: 1. What is the essence of exposure? The object pointed to by module.exports 2. In the CommonJs module specification, module.exports and exports.xxx cannot be mixed. 3. If mixed, use module.exports as the main */ exports .peiqi = [ 1 , 3 , 5 , 7 , 9 ] module .exports = function haha () { console .log( 'haha' ) } //app.js /* * The main file, used to summarize the various modules * Note: When introducing the module: * 1. If the imported module is a third-party module, write the module name directly. * 2. If the imported module is a custom module, the path must be written, and ./must be added. * */ let module1 = require ( './modules/module1.js' ) let {data,test} = require ( './modules/module1.js' ) //At the same time of introduction, perform deconstruction assignment let module2 = require ( './modules/module2.js' ) let module3 = require ( './modules/module3.js' ) let uniq = require ( 'uniq' ) //How to use a module depends on: what the module exposes. console .log(module1.data); module1.test(); module2.haha(); console .log(module3.peiqi); console .log(uniq([ 1 , 3 , 2 , 5 , 4 , 3 , 6 , 7 , 11 , 10 , 9 , 8 ])); console .log(data) test() console .log( require ( './modules/module1' ).data) //Verify the built-in relationship console .log( module .exports === exports ) console .log( module .exports) console .log( exports ) //Introducing the display page of the module-index.html <body> < script type = "text/javascript" src = "./js/dist/bundle.js" > </script > </body> Copy code

4.2 ES6 modular specification (emphasis!)

1. Grammar:

1) Export module: export separately exposed, unified exposure, default exposure, mixed exposure is all before

2) Import modules: import Note that the introduction of separate and unified exposure is not object deconstruction.

Note: It is recommended to use the default exposure to avoid naming conflicts. Separate exposure and unified exposure may cause naming conflicts.

2. Install babel-cli, babel-preset-es2015 and browserify:

1) Install browserify globally: npm install browserify -g

2) Partially install babel-preset-es2015: npm install babel-preset-es2015 -D

3) Create a .babelrc file (specify specific tasks for babel), the content is as follows:

{ "presets": ["es2015"] } Copy code

3. Realization:

1) Use Babel to compile ES6 into ES5 code babel source file path -d file path after compilation

2) Use Browserify to compile and package js browserify source file path/source file -o file path/file after compilation

Note: If the source file path here is the file path processed by babel!

Examples:

//module1.js /* * module1 uses the method of [respectively exposed] * */ export let data = 'atguigu' export function demo1 () { console .log( `I am the demo function in module1`, data.toUpperCase()) } export function test1 () { console .log( 'I am the test function in module1 ' , data.toLowerCase()) } //module2.js /* * module2, using [Unified Exposure] * */ //arr is private data, do not expose let arr = [ 1 , 3 , 5 , 7 , 9 ] function demo2 () { console .log( 'I am the demo2 function in module2' , arr) } function test2 () { console .log( 'I am the test2 function in module2' , arr) } //Unified exposure ( short version) export {demo2,test2} //Not an object //Unified exposure (full version) /* export { demo2 as haha1,//can be exposed at the same time, assign an alias test2 as haha2 }*/ //module3.js /* * Module3 uses [default exposure], which can only be exposed once. * */ export default 2 //export default { //name:'kobe', //age:25, //speak(){ //console.log(`My name is ${this.name}, I The age of is: ${this.age}`); //} //} //module4.js /* * module4: mixed exposure * */ //respectively expose export let arr0 = [ 1 , 3 , 5 , 7 , 9 , 10 ] export function bar () { console .log( 'module4-------bar()' ) } export function foo () { console .log( 'module4-------foo()' ) } //Unified exposure let str = 'hello,atguigu' let student = { name : 'peiqi' , age : 18 } class Dog { constructor ( name,age ) { this .name = name; this .age = age; } run () { console .log( 'I'm running' ) } } let d1 = new Dog( 'wc' , 3 ) export {str,student,d1} //The default exposure export default { school : 'atguigu' , price : '15K' } //app.js /* * The main file, used to summarize the various modules * */ //In the es6 modular specification, which way to introduce depends on the way it is exposed. //Introduce module1, module1 is [respectively exposed] import {data,demo1,test1} from './module1' //[Another way of writing]: Import module1, module1 is [respectively exposed], this way of introduction The content exposed by module1 will be collected into an object //import * as haha from'./module1' //Introducing module2, module2 is the [unified exposure] import {demo2,test2} from './module2' //[another way of writing], the introduction of module2, module2 is [unified exposure], this import method will The content exposed by module2 is collected into an object //import * as haha2 from'./ module2 ' //Introduce module2, module2 is [unified exposure] (the exposed content is aliased in module2) //import {haha1, haha2} from'./module2' //Introduce module3, module3 is [default exposure] import module3 from './module3' //If the module is exposed by default, try not to use the following writing //import * as module3 from'./module3' //Introduce module4, a variety of exposure methods are used in module4. When mixed exposure is introduced, the default exposure is written as import module4,{arr0,bar,foo,str,student,d1} from './module4' //Introduce the third-party module uniq. Almost all third-party modules are exposed by default. Import the uniq from 'the uniq' console .log(data) demo1() test1() demo2() test2() /*console.log(module3.name) console.log(module3.age) module3.speak()*/ console .log(module3) console .log(uniq([ 1 , 3 , 3 , 3 , 2 , 5 , 4 , 6 , 7 , 9 , 8 , 11 , 10 ])); console .log(arr0,str,student,d1) bar() foo() d1.run() console .log(module4) //Introduce test in index.html page <body> //Introduce babel to convert ES5 syntax and browserify translated dist.js < script type = "text/javascript" src = "./js/dist/dist.js" > </script > </body> Copy code

4.3 AMD specification

1. Grammar:

1- Exposure

1) Define a module without dependencies

define(function(){ return module }) Copy code

2) Define dependent modules

define(['module1','module2'], function(m1, m2){ return module }) Copy code

2- Introduce the use of modules

require(['module1','module2'], function(m1, m2){ Use m1/m2 }) Copy code

2. Realize

1) Download require.js

2) Import require.js into the project: js/libs/require.js

Examples:

//module1.js /* * Define a module1 with no dependencies * */ define( function () { //----- let data = 'atguigu' // function getDataL() { return data.toLowerCase() } function getDataU() { return data.toUpperCase() } return {getDataL,getDataU} // }) //module2.js /* * module2,module2 module1 module1 --data * */ define(['module1'],function (module1) { let msg = '0719 ' //module1 data module2 msg function getDataAndMsg() { return module1.getDataL() + msg } return getDataAndMsg }) //app.js /* * AMD js ( ) * */ // requirejs.config({ baseUrl: './js/', //baseUrl index.html // paths: { module1: 'modules/module1', module2: 'modules/module2', jquery: 'lib/jquery-1.10.1' //jquery } }); requirejs(['module2','jquery'],function (m2,$) { console.log($) console.log(m2()); $('body').css('background','skyblue') }); //Introducing test in index.html page < body > <!--In AMD modularization, a special introduction method should also be used in the main page --> < script data-main = "./js/app.js" src = "./js/lib/require.js" > </Script > </body > copy the code

4.4CMD specification

1. Grammar:

1- Exposure-The syntax is a mixture of CommonJS and AMD

1) Define a module without dependencies

define(function(require, exports, module){ exports.xxx = value module.exports = value }) Copy code

2) Define dependent modules

define(function(require, exports, module){ //Introduce dependent modules (synchronization) var module2 = require('./module2') //Introduce dependent modules (asynchronous) require.async('./module3', function (m3) { }) //Exposure module exports.xxx = value }) Copy code

2- Introduce the use of modules-the syntax is a mixture of CommonJS and AMD

define(function (require) { var m1 = require('./module1') var m4 = require('./module4') m1.show() m4.show() }) Copy code

3- How to use the module (in html): seajs.use()

2. Realize

1) Download Sea.js

2) Import Sea.js into the project: js/libs/Sea.js

Examples:

//module1.js /* * Define a module without dependencies, module1 * */ define( function ( require , exports , module ) { let data = '--------module1---------' function getData () { console .log(data) } module .exports = {getData} }) //module2.js /* * Define a module without dependencies, module2 * */ define( function ( require , exports , module ) { let data = '--------module2---------' function getData () { console .log(data) } module .exports = {getData} }) //module3.js /* * Define a module without dependencies, module3 * */ define( function ( require , exports , module ) { let data = '--------module3---------' function getData () { console .log(data) } module .exports = {getData} }) //module4.js /* * Define a dependent module, module4, which depends on module2 and module3 * */ define( function ( require , exports , module ) { let data = '--------module4---------' //Introduce module2-----Introduce let module2 synchronously = require ( './module2' ) module2.getData() //Introduction of module3-----asynchronous introduction of require .async( './module3' , function ( m3 ) { m3.getData() }) function getData () { console .log(data) } module .exports = {getData} }) //main.js /* * The main js file, used to summarize the various modules * */ define( function ( require ) { let module1 = require ( './module1' ) let module4 = require ( './module4' ) module1.getData() module4.getData() }) //Introduce test in index.html page <body> < script type = "text/javascript" src = "js/libs/sea.js" > </script > < script type = "text/javascript" > seajs.use( './js/modules/main' ) </script > </body> Copy code