JavaScript模块化

模块化的含义:把逻辑分块、各自封装、相互独立,同时自行决定引入哪些外部模块以及暴露自身的哪些模块。

模块化的好处

  1. 避免命名冲突(减少命名空间污染)
  2. 更好的分离,按需加载
  3. 更高复用性
  4. 高可维护性

JS中常见的模块:

1.  IIFE模式:匿名函数自调用(闭包)

2.  CommonJS:同步方式加载模块

3.  AMD:Asynchronous Module Definition 异步模块定义

4.  CMD:引用的是seajs,同步模块

5.  UMD:Universal Module Definition 兼容AMD和CommonJS规范,而且兼容全局引入

6.  ES6 Module:浏览器和服务器通用的解决方案

详解:

1. IIFE模式:匿名函数自调用(闭包)

环境:浏览器端

原理:利用闭包原理创造出一个独有的函数作用域来保护私有变量

例子:

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

2. CommonJS:同步方式加载模块

环境:服务器端(Node.js)

应用:

  • 暴露模块:module.exports = value或者exports.xx = value(exports 是一个导出的对象)
  • 引入模块:require(xx),如果是第三方模块,xxx 为模块名,如果为自定义模块,xxx 为模块的文件路径

特点

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。

例子:

// module.js
let arr = [1, 2, 2, 3, 3];
module.exports = {
  arr,
};
// app.js
let module1 = require("./module.js");

console.log(module1.arr);

3. AMD:Asynchronous Module Definition 异步模块定义,非同步的方式加载模块

应用:

  • 暴露模块:
    // 定义没有依赖的模块
    define(function() {
      return 模块;
    });
    // 定义有依赖的模块
    define(["module1", "module2"], function(m1, m2) {
      return 模块;
    });
  • 引入模块:
    require(["module1", "module2"], function(m1, m2) {
      使用m1 和 m2;
    });

例子:

// module.js
// 定义模块
define(function() {
  let url = window.location.href;

  function getUrl() {
    return url.toUpperCase();
  }
  // 暴露模块
  return {
    getUrl,
  };
});
// main.js
(function() {
  require(["module.js"], function(module) {
    let currentUrl = module.getUrl();
    alert("当前页面的URl:" + currentUrl);
  });
})();

4. CMD:引用的是seajs,同步模块

环境:浏览器环境

特点:CMD 是 AMD 在基础上改进的一种规范,和 AMD 不同在于依赖模块的执行机制不同,CMD 是就近依赖,而 AMD 是前置依赖。

应用:

  • 导入:define(function(require, exports, module){})
  • 导出:define(function(){return '值'})

例子:

// 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";
});

5. UMD:Universal Module Definition 兼容AMD和CommonJS规范,而且兼容全局引入

环境:服务器环境和浏览器端

原理:

  • 先判断是否支持 AMD(define 是否存在),存在则使用 AMD 方式加载模块;
  • 再判断是否支持 Node.js 模块格式(exports 是否存在),存在则使用 Node.js 模块格式;
  • 前两个都不存在,则将模块公开到全局(window 或 global)。

例子:

(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,
  };
});

6. ES6 Module:替代CommonJS和AMD规范,成为浏览器和服务器通用的解决方案

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。

环境:服务器端和浏览器端

特点:

  • 按需加载(编译时加载)
  • import 和 export 命令只能在模块的顶层,不能在代码块之中(如:if 语句中),import()语句可以在代码块中实现异步动态按需动态加载

语法:

  • 导出:export 或 export default
  • 导入:import { module1, module2 } from ‘模块路径’
  • 动态导入:import(‘模块路径’).then(...)

和CommonJS的区别:

  • CommonJS输出的是一个值的拷贝,ES6模块输出的是值的引用
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口
  • CommonJS 模块的 require()是同步加载模块,ES6 模块的 import 命令是异步加载,有一个独立的模块依赖的解析阶段。

例子:

// 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

总结

  1. CommonJS规范主要用于服务端编程,加载模块是同步的,这并不适合在浏览器环境,因为同步意味着阻塞加载,浏览器资源是异步加载的,因此有了AMD、CMD解决方案。
  2. AMD规范在浏览器环境中异步加载模块,而且可以并行加载多个模块。不过,AMD规范开发成本高,代码在阅读和书写比较困难,模块定义方式的语义不流畅。
  3. CMD规范和AMD规范很相似,都是浏览器编程,依赖就近,延迟执行,可以很容易在Node.js中运行。不过,不依赖SPM打包,模块的加载逻辑偏重。
  4. ES6在语言标准的层面上,实现了模块功能,而且实现的非常简单,完全可以取代CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值