Home > Web Front-end > JS Tutorial > body text

Detailed introduction to JavaScript modular programming (code examples)

不言
Release: 2019-03-11 17:07:08
forward
2844 people have browsed it

This article brings you a detailed introduction to JavaScript modular programming (code examples). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

What is modularity?

A module is a set of methods to achieve a specific function, and modularization is to create its own scope for the module code, exposing only public methods and variables to the outside, and these methods are highly detachable from each other. coupling.

Why do you need modular programming when writing JS?
When writing the front-end, we only processed some form submissions and click interactions on the web page. The concept of JS modularity was not strengthened. The front-end logic became complex, the interactions became more, and the amount of data became larger and larger. At this time, the front-end's demand for JS modular programming has become stronger.

In many scenarios, we need to consider modularity:

  1. Many people in the team collaborate and need to quote other people’s code
  2. During project handover, we need to read and re- Construct other people's code
  3. When reviewing code, check whether your code is standardized and whether there are problems
  4. After writing the code, review whether the code you wrote is beautiful:)
  5. Different The environment and environment variables are different

Based on the above scenarios, therefore, the current JS modularization mainly has these purposes:

  1. Code reusability
  2. Functional code loose coupling
  3. Resolve naming conflicts
  4. Code maintainability
  5. Code readability

First give the conclusion: JS module Programming has gone through several stages:

  1. Code encapsulation in the form of namespace
  2. Namespace created through immediate execution function (IIFE)
  3. Server-side runtime Nodejs's CommonJS specification
  4. AMD/CMD specification that will run modularly on the browser side
  5. Compatible with CMD and AMD's UMD specification
  6. ES Module supported through language standards

Let me give you the conclusion first:

Detailed introduction to JavaScript modular programming (code examples)

1. Namespace

We know that before ES6, JS did not have In block scope, the isolation of private variables and methods mainly relies on function scope, and the isolation of public variables and methods mainly relies on object attribute references.

Encapsulation function

When JS did not have modular specifications, some common and underlying functions were abstracted and separated into functions to achieve modularity. :
For example, write a utils.js tool function file

//  utils.js
function add(x, y) {
    if(typeof x !== "number" || typeof y !== "number") return;
    return x + y;
}

function square(x) {
    if(typeof x !== "number") return;
    return x * x;
}

<script></script>
<script>
    add(2, 3);
    square(4);
</script>
Copy after login

By dividing the js function file, the public function at this time is actually mounted under the global object window. When others also want to define one When calling the add function, or when multiple js files are merged and compressed, there will be naming conflicts.

Mounted under global variables:

Later we thought of mounting functions under global object literals, using the concept of JAVA packages, hoping to ease naming seriousness of the conflict.

var mathUtils1 = {
    add: function(x, y) {
        return x + y;
    },
}

var mathUtils2 = {
    add: function(x, y, z) {
        return x + y + z;
    },
}

mathUtils.add();

mathUtils.square();
Copy after login

This method still creates global variables, but if the path of the package is very long, the reference method may end up referencing the code in the manner of module1.subModule.subSubModule.add .

IIFE
Considering that the module has private variables, we use IIFE (immediate execution expression) to create a closure to encapsulate the private variables:

var module = (function(){
    var count = 0;
    return {
        inc: function(){
            count += 1;
        },
        dec: function(){
            count += -1;
        }
    }
})()

module.inc();
module.dec();
Copy after login

Such private variables It is inaccessible to the outside. What if the module needs to introduce other dependencies?

var utils = (function ($) {
    var $body = $("body"); 
    var _private = 0;
    var foo = function() {
        ...
    }
    var bar = function () {
        ...
    }
    
    return {
        foo: foo,
        bar: bar
    }
})(jQuery);
Copy after login

The above method of encapsulating modules is called: module mode. In the era of jQuery, the module mode was widely used:

<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
Copy after login

jQuery plug-ins must be after the JQuery.js file, in the loading order of the files Being strictly restricted, the more dependencies there are, the more confusing the dependency relationships are, and the easier it is to make mistakes.

2. CommonJS

The emergence of Nodejs allows JavaScript to run in a server-side environment. At this time, there is an urgent need to establish a standard to implement a unified module system, which later became CommonJS.

// math.js
exports.add = function(x, y) {
    return x + y;
}

// base.js
var math = require("./math.js");
math.add(2, 3);  // 5

// 引用核心模块
var http = require('http');
http.createServer(...).listen(3000);
Copy after login

CommonJS stipulates that inside each module, module represents the current module. This module is an object with attributes such as id, filename, loaded, parent, children, exports, etc. The module.exports attribute represents the external output of the current module. interface, other files load the module, which actually reads the module.exports variable.

// utils.js
// 直接赋值给 module.exports 变量
module.exports = function () {
    console.log("I'm utils.js module");
}

// base.js
var util = require("./utils.js")
util();  // I'm utils.js module

或者挂载到 module.exports 对象下
module.exports.say = function () {
    console.log("I'm utils.js module");
}

// base.js
var util = require("./utils.js")
util.say();
Copy after login

For convenience, Node provides an exports free variable for each module, pointing to module.exports. This is equivalent to having a line like this at the head of each module.

var exports = module.exports;
Copy after login

exports and module.exports share the same reference address. If you directly assign a value to exports, the two will no longer point to the same memory address, but it will not take effect on module.exports in the end.

// module.exports 可以直接赋值
module.exports = 'Hello world';  

// exports 不能直接赋值
exports = 'Hello world';
Copy after login

CommonJS summary:
CommonJS specification loading module is synchronous and used on the server side. Since CommonJS will load the built-in module into the memory at startup, it will also load the module. The passed modules are placed in memory. Therefore, there will not be a big problem using synchronous loading in the Node environment.

In addition, the CommonJS module loads a copy of the output value. In other words, if the output value of the external module changes, the import value of the current module will not change.

三、AMD

CommonJS 规范的出现,使得 JS 模块化在 NodeJS 环境中得到了施展机会。但 CommonJS 如果应用在浏览器端,同步加载的机制会使得 JS 阻塞 UI 线程,造成页面卡顿。

利用模块加载后执行回调的机制,有了后面的 RequireJS 模块加载器, 由于加载机制不同,我们称这种模块规范为 AMD(Asynchromous Module Definition 异步模块定义)规范, 异步模块定义诞生于使用 XHR + eval 的开发经验,是 RequireJS 模块加载器对模块定义的规范化产出。

AMD 的模块写法:

// 模块名 utils
// 依赖 jQuery, underscore
// 模块导出 foo, bar 属性
<script></script>

// main.js
require.config({
  baseUrl: "script",
  paths: {
    "jquery": "jquery.min",
    "underscore": "underscore.min",
  }
});

// 定义 utils 模块,使用 jQuery 模块
define("utils", ["jQuery", "underscore"], function($, _) {
    var body = $("body");
    var deepClone = _.deepClone({...});
    return {
        foo: "hello",
        bar: "world"
    }
})
Copy after login

AMD 的特点在于:

  1. 延迟加载
  2. 依赖前置

AMD 支持兼容 CommonJS 写法:

define(function (require, exports, module){
  var someModule = require("someModule");
  var anotherModule = require("anotherModule");

  someModule.sayHi();
  anotherModule.sayBye();

  exports.asplode = function (){
    someModule.eat();
    anotherModule.play();
  };
});
Copy after login

四、CMD

SeaJS 是国内 JS 大神玉伯开发的模块加载器,基于 SeaJS 的模块机制,所有 JavaScript 模块都遵循 CMD(Common Module Definition) 模块定义规范.

CMD 模块的写法:

<script></script>
<script>
// seajs 的简单配置
seajs.config({
  base: "./script/",
  alias: {
    "jquery": "script/jquery/3.3.1/jquery.js"
  }
})

// 加载入口模块
seajs.use("./main")
</script>

// 定义模块
// utils.js
define(function(require, exports, module) {
  exports.each = function (arr) {
    // 实现代码 
  };

  exports.log = function (str) {
    // 实现代码
  };
});

// 输出模块
define(function(require, exports, module) {
  var util = require('./util.js');
  
  var a = require('./a'); //在需要时申明,依赖就近
  a.doSomething();
  
  exports.init = function() {
    // 实现代码
    util.log();
  };
});
Copy after login

CMD 和 AMD 规范的区别:  
AMD推崇依赖前置,CMD推崇依赖就近:  
AMD 的依赖需要提前定义,加载完后就会执行。
CMD 依赖可以就近书写,只有在用到某个模块的时候再去执行相应模块。
举个例子:

// main.js
define(function(require, exports, module) {
  console.log("I'm main");
  var mod1 = require("./mod1");
  mod1.say();
  var mod2 = require("./mod2");
  mod2.say();

  return {
    hello: function() {
      console.log("hello main");
    }
  };
});

// mod1.js
define(function() {
  console.log("I'm mod1");
  return {
    say: function() {
      console.log("say: I'm mod1");
    }
  };
});

// mod2.js
define(function() {
  console.log("I'm mod2");
  return {
    say: function() {
      console.log("say: I'm mod2");
    }
  };
});
Copy after login

以上代码分别用 Require.js 和 Sea.js 执行,打印结果如下:  
Require.js:  
先执行所有依赖中的代码

I'm mod1
I'm mod2
I'm main
say: I'm mod1
say: I'm mod2
Copy after login

Sea.js:  
用到依赖时,再执行依赖中的代码

I'm main

I'm mod1
say: I'm mod1
I'm mod2
say: I'm mod2
Copy after login

五、UMD

umd(Universal Module Definition) 是 AMD 和 CommonJS 的兼容性处理,提出了跨平台的解决方案。

(function (root, factory) {
    if (typeof exports === 'object') {
        // commonJS
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        // AMD
        define(factory);
    } else {
        // 挂载到全局
        root.eventUtil = factory();
    }
})(this, function () {
    function myFunc(){};

    return {
        foo: myFunc
    };
});
Copy after login

应用 UMD 规范的 JS 文件其实就是一个立即执行函数,通过检验 JS 环境是否支持 CommonJS 或 AMD 再进行模块化定义。

六、ES6 Module

CommonJS 和 AMD 规范都只能在运行时确定依赖。而 ES6 在语言层面提出了模块化方案, ES6 module 模块编译时就能确定模块的依赖关系,以及输入和输出的变量。ES6 模块化这种加载称为“编译时加载”或者静态加载。

Detailed introduction to JavaScript modular programming (code examples)

写法:

// math.js
// 命名导出
export function add(a, b){
    return a + b;
}
export function sub(a, b){
    return a - b;
}
// 命名导入
import { add, sub } from "./math.js";
add(2, 3);
sub(7, 2);

// 默认导出
export default function foo() {
  console.log('foo');
}
// 默认导入
import someModule from "./utils.js";
Copy after login
ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

另,在 webpack 对 ES Module 打包, ES Module 会编译成 require/exports 来执行的。

总结

JS 的模块化规范经过了模块模式、CommonJS、AMD/CMD、ES6 的演进,利用现在常用的 gulp、webpack 打包工具,非常方便我们编写模块化代码。掌握这几种模块化规范的区别和联系有助于提高代码的模块化质量,比如,CommonJS 输出的是值拷贝,ES6 Module 在静态代码解析时输出只读接口,AMD 是异步加载,推崇依赖前置,CMD 是依赖就近,延迟执行,在使用到模块时才去加载相应的依赖。

The above is the detailed content of Detailed introduction to JavaScript modular programming (code examples). For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template