模块化规范

一、参考资料:
1、介绍模块化发展的历程(opens new window)
2、各模块化规范思维导图
相关问题
1、模块化的作用
抽取公共代码、隔离作用域、依赖管理
2、模块化历史
无模块化(IIFE)->CommonJS -> AMD -> CMD -> ESModule,特殊UMD

0、IIFE

在单独的函数作用域中执行代码,避免冲突

(function() {
  return {
    data: []
  }
})(jQuery) // 注入对象

1、CommonJS

  • 服务器node,浏览器端webpack | browserfy
  • 文件即模块,模块加载同步:服务器端模块加载是运行时同步加载,浏览器模块加载是提前编译打包处理
  • exports = module.exports 输出(不能给exports赋值,导致与module引用断开),require引入
  • 缓存:require值会缓存,通过require引用文件时,会将文件执行一遍后,将结果通过浅克隆的方式,写入全局内存,后续require该路径,直接从内存获取,无需重新执行文件
// a.js
var name = "morrain";
var age = 18;
exports.name = name;
exports.getAge = function() {
  return age;
};

// b.js
var a = require("a.js");
console.log(a.name); // 'morrain'
a.name = "rename";
console.log(a.name); // 'rename'
var b = require("a.js");
console.log(b.name); // 'rename'
  • 模块输出是值的拷贝,一旦输出,模块内部变化后,无法影响之前的引用,而ESModule是引用拷贝
// b.js
var a = require("./a");
console.log(a.age); // 'morrain'
a.setAge(19);
console.log(a.age); // 'rename'
  • CommonJS运行时加载,ESModule编译阶段引用
    • CommonJS在引入时是加载整个模块,生成一个对象,然后再从这个生成的对象上读取方法和属性
    • ESModule不是对象,而是通过export暴露出要输出的代码块,在import时使用静态命令的方法引用指定的输出代码块,并在import语句处执行这个要输出的代码,而不是直接加载整个模块

2、AMD

  • AMD(Asynchronous module definition)异步的模块定义,浏览器端运行,所有模块默认都是异步加载
  • 代码requireJS:https://requirejs.org/docs/api.html
  • 使用:定义define、加载require、配置config
// 定义:define(id?, depencies?, factory);
// utils和bar可直接使用
define("foo", ["utils", "bar"], function(utils, bar) {
  utils.add(1, 2);
  return {
    name: "foo"
  };
});
// 配置模块:可以直接配置依赖路径
require.config({
  paths: {
    jquery: "https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"
  }
});

// 加载模块:提前加载
require(["jquery"], function(jquery) {
  // ...
});

// 提前加载执行顺序
// RequireJS
define("a", function() {
  console.log("a load");
  return {
    run: function() {
      console.log("a run");
    }
  };
});

define("b", function() {
  console.log("b load");
  return {
    run: function() {
      console.log("b run");
    }
  };
});

require(["a", "b"], function(a, b) {
  console.log("main run");
  a.run();
  b.run();
});

// a load
// b load
// main run
// a run
// b run

3、CMD

  • 代表seaJS,特点支持动态引入依赖文件,按需加载
  • 整合了commonJS和AMD的特点,浏览器端运行
// 引入require
var fs = require("fs"); // 同步
require.async("./module3", function(m3) {}); //异步

// sea.js,按需引入
define("a", function(require, exports, module) {
  console.log("a load");
  exports.run = function() {
    console.log("a run");
  };
});

define("b", function(require, exports, module) {
  console.log("b load");
  exports.run = function() {
    console.log("b run");
  };
});

define("main", function(require, exports, module) {
  console.log("main load");
  var a = require("a");
  a.run();
  var b = requrie("b");
  b.run();
});
seajs.use("main");
// main run
// a load
// a run
// b load
// b run

4、UMD

兼容CommonJS和AMD模块化语法,作为一种同构(isomorphic)的模块化解决方案,判断这些模块化规范的特征值,判断出当前究竟在哪种模块化规范的环境下,然后把模块内容用检测出的模块化规范的语法导出。

(function(self, factory) {
  if (typeof module === "object" && typeof module.exports === "object") {
    // 当前环境是 CommonJS 规范环境
    module.exports = factory();
    // console.log("CommonJS");
  } else if (typeof define === "function" && define.amd) {
    // 当前环境是 AMD 规范环境
    define(factory);
    // console.log("AMD");
  } else {
    // 什么环境都不是,直接挂在全局对象上
    self.umdModule = factory();
    // console.log("global");
  }
})(this, function() {
  return function() {
    return Math.random();
  };
});

5、ESModule 规范

  • 服务端和浏览器端通用,ESModule 是由 JS 解释器实现,CommonJS和AMD是在宿主环境中运行时实现
  • import输入、export输出(export default Module、export default Module)
// export 一个模块只能有一个默认输出
export var fistName = 'scp'
export var lastName = 'scp'
var fistName = 'scp'
var lastName = 'scp'
export {firstName, lastName as b}
export default firstName

// import 无{}为默认,*为模块整体加载
export function crc32() {}
import {crc32} from 'crc32'

export default  function crc32() {}
import crc32 from 'crc32'

import * as circle from './circle'
circle.area(4)
circle.circumference(14)
posted @ 2023-02-27 14:03  中亿丰数字科技  阅读(34)  评论(0)    收藏  举报