头图

Understand once-JavaScript modularization detailed

JavaScript-模块 _1_.png

The meaning of modularity

Split the code into independent blocks, and then connect these blocks using the module pattern to achieve different functions.

Just like the puzzles played in childhood, different puzzles can be combined into any shape.

The idea behind this model is also very simple: divides the logic into blocks and encapsulates them independently, and at the same time decides to introduce and execute those external modules and those modules that expose themselves.

This basic idea is the foundation of all JavaScript module systems.

The code case address in the article: https://github.com/AnsonZnl/JS-Modules-Sample

The benefits of modularity

  • Avoid naming conflicts (reduce namespace pollution)
  • Better separation, on-demand loading
  • Higher reusability
  • High maintainability

Common modules in JS

IIFE mode: anonymous function self-calling (closure)

The main application is on the browser side.

Use the principle of closure to create a unique function scope to store private variables, achieving a modular effect.

uses

HTML

<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
  console.log(myModule.get()); // output-data(获取内部数据)
  myModule.set("new data"); // 设置内部数据
  console.log(myModule.data); //output-undefined (不能访问模块内部数据)
  myModule.data = "xxxx"; //不是修改的模块内部的data
  console.log(myModule.get()); //output-new data 修改后的值
</script>

JS

// module.js文件
(function(window) {
  let data = "data";
  //获取数据
  function get() {
    return data;
  }
  // 修改数据
  function set(val) {
    data = val;
  }
  //暴露行为
  window.myModule = {
    get,
    set,
  };
})(window);

CommonJS

The main application is on the server side. If running on the browser side, other tools (Browserify) are needed.

exposed module: module.exports = value or exports.xx = value (exports is an exported object)

introduces the module: require(xx) , if it is a third-party module, xxx is the module name, if it is a custom module, xxx is the file path of the module.

features

  • All code runs in the module scope and will not pollute the global scope.
  • The module can be loaded multiple times, but it will only run once when it is loaded for the first time, and then the running result is cached, and when it is loaded later, the cached result is directly read. To make the module run again, the cache must be cleared.
  • The order in which the modules are loaded is in the order in which they appear in the code.

uses
Install uniq functions in Node.

npm init
npm install uniq --save
// module.js
let arr = [1, 2, 2, 3, 3];
module.exports = {
  arr,
};
// app.js
let module1 = require("./module.js");
let uniq = require("uniq");

console.log(uniq(module1.arr)); // [1,2,3]

AMD

The full name is Asynchronous Module Definition-Asynchronous Module Definition

Unlike CommonJS, AMD uses an asynchronous method to load modules.

basic syntax

Define the exposed module

// 定义没有依赖的模块
define(function() {
  return 模块;
});
// 定义有依赖的模块
define(["module1", "module2"], function(m1, m2) {
  return 模块;
});

Introduce and use modules

require(["module1", "module2"], function(m1, m2) {
  使用m1 和 m2;
});

use case

<!-- index.html -->
<body>
  <!-- 引入require.js并指定js主文件的入口 -->
  <script
    data-main="main"
    src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"
  ></script>
</body>
// main.js
(function() {
  require(["module.js"], function(module) {
    let currentUrl = module.getUrl();
    alert("当前页面的URl:" + currentUrl);
  });
})();
// module.js
// 定义模块
define(function() {
  let url = window.location.href;

  function getUrl() {
    return url.toUpperCase();
  }
  // 暴露模块
  return {
    getUrl,
  };
});

For more usage methods, please refer to: https://requirejs.org/

CMD

CMD--- is the standardized output of SeaJS's module definition in the promotion process. It is a synchronous module definition. It is a standard of SeaJS. SeaJS is an implementation of the CMD concept. SeaJS is a JS framework for module development provided by the Taobao team. .

When it is used and when it is introduced, it is returned when it is used. This is a synchronization concept.

features: CMD is a specification improved on the basis of AMD. The difference from AMD is that the execution mechanism of dependent modules is different. CMD is dependent on the nearest, and AMD is dependent on the front.

environment: browser environment

syntax:

  • Import: define(function(require, exports, module){})
  • Export: define(function(){return'value'})

use

// main.js
define(function(require, exports, module) {
  var moduleA = require("./module.js");
  alert(moduleA.a); // 打印出:hello world
});
// module.js
define(function(require, exports, module) {
  exports.a = "hello world";
});
<body>
  <script
    data-main="main"
    src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"
  ></script>
</body>

For Sea.js usage, please refer to: https://seajs.github.io/seajs/docs/

UMD

The full name of Universal Module Definition is known by the name. It is characterized by compatibility with AMD and CommonJS specifications, and compatibility with global introduction.

environment: server environment and browser side

implementation principle of 160b06148ae0fc UMD is very simple:

  • First judge whether AMD is supported (whether define exists), and if it exists, use AMD to load the module;
  • Then judge whether it supports the Node.js module format (whether exports exist), and if it exists, use the Node.js module format;
  • If the first two do not exist, the module will be exposed to the global (window or global)

uses

(function(root, factory) {
  if (typeof define === "function" && define.amd) {
    //AMD
    define(["jquery"], factory);
  } else if (typeof exports === "object") {
    //Node, CommonJS之类的
    module.exports = factory(require("jquery"));
  } else {
    //浏览器全局变量(root 即 window)
    root.returnExports = factory(root.jQuery);
  }
})(this, function($) {
  //方法
  function myFuncA() {} // 私有方法,因为没有返回
  function myFuncB() {} // 公共方法,因为返回了

  //暴露公共方法
  return {
    myFuncB,
  };
});

The CND of jQuery that you usually introduce is UMD. The source code can be viewed: https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js

ES6 Module

Before ES6, modularization was mainly promoted by the community, and there were two CommonJS and AMD. The former was used for servers and the other was used for browsers. The emergence of ES6 modules would completely replace CommonJS and AMD specifications and become browsers and A universal solution for servers.

The design idea of ES6 modules is to be as static as possible, so that the dependencies of the modules and the input and output variables can be determined at compile time. Both CommonJS and AMD modules can only determine these things at runtime. For example, CommonJS modules are objects, and object attributes must be searched when typing.

Features :

  • Load on demand (load at compile time)
  • The import and export commands can only be at the top level of the module, not in the code block (for example: in the if statement), the import() statement can be dynamically loaded in the code block to achieve asynchronous dynamic on-demand dynamic loading

environment: server environment and browser side

syntax:

  • Import: import {modules1,modules1,} from'module path'
  • Export: export or export default
  • Dynamic import: import('module path').then(..)
    <!-- tree-shaking -->

uses

Install Babel in Node first:

npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
npm install --save @babel/polyfill
# 然后运行
npx babel-node main.js
// modules/double.js
let mes = "Hello Modules for double";
function sum(value) {
  return `${mes} - ${value * 2}`;
}
export default {
  mes,
  sum,
};
// main.js
import module from "./modules/double";
console.log(module.sum(10)); // Hello Modules for double - 20

In the browser

difference

  • The difference with CommonJS:

    • The output of the CommonJS module is a value worth copying, and the output of the ES6 module is a reference to the value
    • The CommonJS module is loaded at runtime, and the ES6 module is the output interface at compile time
    • The require() of the CommonJS module is to load the module synchronously, and the import command of the ES6 module is to be loaded asynchronously, and there is an independent module dependency analysis stage.

Disadvantages
The current support of the browser and server is not very good. At this stage, some tools are needed ( Babel ).

  • <script type="module" src="./foo.js"></script> can be used in the new version of the browser (such as Chrome)
  • Server support (Node) has two modes, namely ES6 module and CommonJS.

    • Starting Node.js v13.2, the default support ES6 module, but need .mjs name suffix, or in package.json modification type field module (recommended)
    • If you use CommonJS, you need to use .cjs as the suffix. You can also set the type field in package.json to modify the commonjs (recommended).

It is best not to mix the two. For more usage methods, please refer to: https://es6.ruanyifeng.com/#docs/module

to sum up

  • The CommonJS specification is mainly used for server-side programming, and the loading module is synchronous, which is not suitable for the browser environment, because synchronization means blocking loading, and browser resources are loaded asynchronously, so there is the AMD CMD solution.
  • The AMD specification loads modules asynchronously in the browser environment, and multiple modules can be loaded in parallel. However, AMD specification development costs are high, code reading and writing are difficult, and the semantics of the module definition method is not smooth.
  • The CMD specification is very similar to the AMD specification. Both are used for browser programming, relying on the nearest, delayed execution, and can be easily run in Node.js. However, relying on SPM packaging, the loading logic of the module is biased
  • ES6 implements the module function at the level of language standards, and the implementation is quite simple, it can completely replace CommonJS and AMD specifications, and become a common module solution for browsers and servers.

reference

original article

九旬的博客
关注我,每周输出一篇前端技术文章, 博客地址:[链接]

关注我,每周输出一篇前端技术文章,

893 声望
1.2k 粉丝
0 条评论
推荐阅读
【译】20个实用的JavaScript技巧
JavaScript不断发展壮大,因为它是最容易上手的语言之一,因此为市场上的新“成为技术怪才”打开了大门。(真假的啊?)的确,JavaScript可以做很多出色的事情!还有很多东西要学习。而且,无论您是JavaScript的新...

九旬4阅读 972

从零搭建 Node.js 企业级 Web 服务器(零):静态服务
过去 5 年,我前后在菜鸟网络和蚂蚁金服做开发工作,一方面支撑业务团队开发各类业务系统,另一方面在自己的技术团队做基础技术建设。期间借着 Node.js 的锋芒做了不少 Web 系统,有的至今生气蓬勃、有的早已夭折...

乌柏木142阅读 11.9k评论 10

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木60阅读 6k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs39阅读 6.2k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木39阅读 7.1k评论 6

CSS 绘制一只思否猫
欢迎关注我的公众号:前端侦探练习 CSS 有一个比较有趣的方式,就是发挥想象,绘制各式各样的图案,比如来绘制一只思否猫?思否猫,SegmentFault 思否的吉祥物,是一只独一无二、特立独行、热爱自由的(&gt;^ω^&lt...

XboxYan42阅读 2.8k评论 14

封面图
还在用 JS 做节流吗?CSS 也可以防止按钮重复点击
举个例子:一个保存按钮,为了避免重复提交或者服务器考虑,往往需要对点击行为做一定的限制,比如只允许每300ms提交一次,这时候我想大部分同学都会到网上直接拷贝一段throttle函数,或者直接引用lodash工具库

XboxYan34阅读 2.2k评论 2

封面图

关注我,每周输出一篇前端技术文章,

893 声望
1.2k 粉丝
宣传栏