模块化基础

111 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

JS语言刚开始只是为了处理一些页面上的交互效果,后来逐渐形成一门复杂的语言,在实现的功能越来越复杂,项目越来越大时,也开始像其他语言一样分文件开发,将每一个文件定义为一个module,在需要使用的模块引入这个module以引用这个模块暴露出来的接口,并且不让其污染全局作用域

常用的模块化规范有: CommonJS、AMD、CMD、ESM

一、CommonJS

CommonJS是最早出现被广泛应用的标准化模块化规范,是node完成初始,开发npm包管理工具时所用的模块化规范。

1.特点

》模块内所有代码都是在模块作用域,不会污染全局作用域
》CommonJS起初就是为了node服务的,他是同步的
》require 读入并执行一个JavaScript文件,返回该模块的exports对象。如果没有发现指定模块,会报错,如果第一次进来,会降exports存入缓存,然后第二次进入后只需要返回缓存中的export即可
》exports 用来向外暴露 API,exports 只能是一个 object 对象,暴漏的 API 须作为该对象的属性。

2.使用

// exports  规定exports为一个对象
module.exports = {
	key: value
}
module.exports.x = value
export.x = value

// require  如果是第三方模块,xxx为模块名;如果是自定义模块,xxx为模块文件路径
require('moment')
require('./math.js')

二、AMD

CommonJS是同步的,只有需要引入的模块加载完成才能执行后面的代码,一般都是服务端使用,如果浏览器端使用,需要借助Browserify将项目打包。而AMD是基于异步开发模式开发的,允许异步完成后调用一个回调函数。

1. 定义和使用

// 定义暴露接口
define(function() {
  // do something
})

// 定义没有依赖的模块
define('math',['exports'],function (exports) {
  exports.getObs = function() {
    return Math.abs(-3);
  }
  // OR:直接返回
  // function getObs() {
  //   return Math.abs(-3);
  // }
  // return {
  //   getObs,
  // };
});

// require

require(['math'], function(math){
   math.getObs()
})

2.require.js

require是遵循amd规范的一个模块化工具,下面结合require.js来使用一下amd规范

》首先require需要下载,官网或者github上都可以(官网地址: requirejs.org/docs/releas…)
》然后把require.js放入一个文件夹下(amd/js/require.js),并在入口文件中引入

amd/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Modular Demo</title>
    <script src="js/require.js" data-main="main"></script>
  </head>
  <body></body>
</html>
》 然后定义模块
// amd/modules/math
define('math',['exports'],function (exports) {
  exports.getObs = function() {
    return Math.abs(-3);
  }
});
》 在main中引入模块

require.config({ baseUrl: "", // 默认在根目录下 paths: { math: "./modules/math", }, }); require(["math"], function (math) { alert(math.getObs()); })

效果: 在这里插入图片描述

二、CMD

CMD也是基于异步服务于浏览器端的一个模块化规范,它结合了ComminJs和AMD的特点,并开发了自己的模块化工具语言SeaJs

1.定义和使用

//定义没有依赖的模块,exports,module三个是默认传入
define(function(exports, module){
  exports.xxx = value
  // Or
  // module.exports = value
})

//定义有依赖的模块
define(function(require, exports, module){
  //同步引入依赖
  var module2 = require('./module2')
  //异步引入依赖
  require.async('./module3', function (m3) {})
  //暴露模块
  exports.xxx = value
})

// 引用
define(function (require) {
  var m1 = require('./module1')
  console.log(m1.xxx)
})

2.SeaJS

》首先SeaJS需要下载,github.com/seajs/seajs
》引入到index.js
<!DOCTYPE html>
<html>
  <head>
    <title>Modular Demo</title>
    <script type="text/javascript" src="js/sea.js"></script>
    <script type="text/javascript">
      seajs.use("./main");
    </script>
  </head>
  <body></body>
</html>
》定义模块
define(function (require, exports, module) {
  module.exports = {
    getRandom: () => {
      return Math.random();
    }
  }
})
》在main.js中引用模块
define(function (require) {
  var math = require("./modules/math.js");
  console.log(math.getRandom());
});

效果 在这里插入图片描述

三 ESM

1.定义和使用

// export
export {
 a: '',
 b: function() {}
}
export default {
 a: ''
}
export const a  = 123;
export const {a, b}  = Obj


// 引入import 必须放在代码的最前面,因为ESM是不编译的
import A from "./a.js"
import { a,b } from "./a.js"

2、ESM和CMD的区别

1.CMD因为输出的export对象是运行完成后才输出接口,而EMD是引用接口,所以编译时就输出接口

2.CMD是有缓存的,模块内数据更新,不会更新到引用的模块,还是使用缓存中的值。而EMD是没有缓存的,他是直接引用了模块中的变量和方法,当有数据改变时,引用的模块也会更新。

参考文章: juejin.cn/post/684490…