JS 模块化学习笔记

JS 模块化学习笔记

一、模块化理解

0. 模块理解

简单理解,具有特定功能的 js 文件,就是 js 模块

  • 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起
  • 块的内部数据/实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信

1. 模块化理解

1.1 什么是模块化?(what)

编码时是按照模块一个一个编码的, 整个项目就是一个模块化的项目

模块化进化历史(在文尾,有兴趣可查看)

1.2 模块化好处?(why)

  • 避免命名冲突(减少命名空间污染)
  • 减少耦合度
  • 复用性更高
  • 可维护性更高

1.3 页面加载多个 js 的问题

页面:

<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript" src="module3.js"></script>
<script type="text/javascript" src="module4.js"></script>

说明

  • 一个页面需要引入多个 js 文件
  • 问题:
    • 请求过多
    • 依赖模糊
    • 难以维护
  • 这些问题可以通过现代模块化编码和项目构建来解决

二、模块化规范

4种模块化规范分别是 CommonJS、AMD、CMD、ES6

2.1 CommonJS

2.1.1 说明

在服务器端:模块的加载在运行时是同步加载的(可能导致阻塞)

在浏览器端:模块需要 Browserify 提前编译打包处理(浏览器不认识 require

2.1.2 基本语法

暴露模块
module.exports = value // 暴露了 exports,value 可以是对象、函数等
exports.xxx = value // 写完整应该是 module.exports.xxx = value,暴露了 exports 这个对象,对象中可以有 xxx 等属性
引入模块
// 1. 当模块是第三方模块时,xxx 为模块名
// 2. 当模块是自定义模块时,xxx 为模块文件路径
require(xxx) 

2.2 AMD(requirejs)

2.2.1 说明

  • Asynchronous Module Definition(异步模块定义)
  • 专门用于浏览器端,模块的加载是异步的

2.4.2 基本语法

暴露模块
//定义没有依赖的模块
define(function(){
    return 模块
})

//定义有依赖的模块
define(['module1', 'module2'], function(m1, m2){
    return 模块
})
引入模块
require(['module1', 'module2'], function(m1, m2){
    使用m1/m2
})

2.3 CMD(了解)

2.3.1 说明

  • Common Module Definition(通用模块定义)
  • 专门用于浏览器端, 模块的加载是异步的
  • 模块使用时才会加载执行

2.3.2 基本语法

暴露模块
//定义没有依赖的模块
define(function(require, exports, module){
    exports.xxx = value
    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')
    var m4 = require('./module4')
    m1.show()
    m4.show()
})

2.4 ES6

2.4.1 说明

ES6 内置了模块化的实现,在浏览器端运行

  • 问题: 所有浏览器还不能直接识别ES6模块化的语法
  • 解决:
    • 使用 BabelES6 ---> ES5 (使用了 CommonJS ) ----浏览器还不能直接运行
    • 使用 Browserify --->打包处理----浏览器可以运行

2.4.2 基本语法

  1. 定义暴露模块:export

    分别暴露

    export xxx
    export yyy
    
    /*示例*/
    // ES6规范 分别暴露
    export function foo() {
        console.log("foo() module1")
    }
    
    export function bar() {
        console.log("bar() module1")
    }
    
    export const arr = [1]
    

    统一暴露

    export {xxx, yyy}
    
    /*示例*/
    // ES6规范 统一暴露
    function fun1() {
        console.log("fun1() module2")
    }
    
    function fun2() {
        console.log("fun2() module2")
    }
    export {
        fun1, fun2
    }
    

    默认暴露

    export default {}
    
    /*示例*/
    // ES6规范 默认暴露
    export default {
        name: 'module3',
        fun3: function () {
            console.log("fun3() module3")
        }
    }
    
  2. 引入使用模块:import
    import {xxx, yyy} from '路径' // 分别暴露和统一暴露 引入方式
    import zzz from '路径' // 默认暴露 引入方式
    
    /*示例*/
    // import $ from 'jquery'
    // 分别暴露和统一暴露 模块
    import { foo, bar } from './module1.js'
    import { fun1, fun2 } from './module2.js'
    
    // 默认暴露 模块
    import xxx from './module3.js'
    
    foo()
    bar()
    fun1()
    fun2()
    xxx.fun3()
    
    $('body').css('background', 'pink')
    

附:模块化进化历史

  1. 全局function模式

    /**
     * 全局函数模式: 将不同的功能封装成不同的全局函数
     * 问题: Global被污染了, 很容易引起命名冲突
     */
    let msg = 'module1'
    function foo () {
      console.log('foo()', msg)
    }
    
    function bar () {
      console.log('bar()', msg)
    }
    
  2. namespace模式

    /**
     * namespace模式: 简单对象封装
     * 作用: 减少了全局变量
     * 问题: 不安全(数据不是私有的, 外部可以直接修改)
     */
    let obj = {
      msg: 'module2',
      foo: function () {
        console.log('foo()', this.msg)
      }
    }
    
  3. IIFE模式

    /**
     * IIFE模式: 匿名函数自调用(闭包)
     * IIFE : immediately-invoked function expression(立即调用函数表达式)
     * 作用: 数据是私有的, 外部只能通过暴露的方法操作
     * 问题: 如果当前这个模块依赖另一个模块怎么办?
     */
    (function (window) {
      let msg = 'module3'
      function foo () {
        console.log('foo()', msg)
      }
      window.module3 = {
        // foo
        foo: foo
      }
    })(window)
    
  4. IIFE模式增强

    /**
     * IIFE模式增强 : 引入依赖(jQuery)
     * 这就是现代模块实现的基石
     */
    
    // 给页面加红色背景
    (function (window, $) {
      let msg = 'module4'
      function foo () {
        console.log('foo()', msg)
      }
      // foo()
      window.module4 = foo
      $('body').css('background', 'red')
    })(window, jQuery)
    
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容