js模块化

JavaScript模块化规范

1. 模块化概述

  1. 什么是模块化?
  • 将程序文件依据一定规则拆分成多个文件,这种编码方式就是模块化的编码方式
  • 拆分出来的每个文件就是一个模块,模块中的数据都是私有的,模块之间相互隔离
  • 同时也能通过一些手段,可以把模块内的指定数据“交出去”,供其他模块使用
  1. 为什么需要模块化?
    随着应用的复杂度越来越高,其代码量和文件数量都会急剧增加,会逐渐引发以下问题:
    1. 全局污染问题
    2. 依赖混乱问题
    3. 数据安全问题

2. 导入与导出的概念

模块化的核心思想是:模块之间是隔离的,通过导入和导出进行数据和功能的共享。

  • 导出(暴露):模块公开其内部的一部分,如变量,函数等,是这些内容可以被其他模块使用;
  • 导入(引入):模块引入和使用其他模块导出的功能,以重用代码和功能

3. 引用问题

  • ES模块化:文件导出数据的时候定义的常量/变量和导出的时候同名的常量使用的是同一块内存空间;ES模块化中,导入的部分是常量,不允许修改的
  • CommonJs:导入的时候定义的变量和导出的时候的变量是复制的关系,不是同一个内存空间

4. 模块化规范

  • CommonJS:服务端应用广泛
    • 导出:export.js
      • exports.name = name;
      • module.exports =
      • 注意:
        1. 每个模块内部的:this,exports,module.exports在初始的时候,都指向同一个空对象,直接导出的话,该空对象就是当前模块导出的数据
        2. 无论如何修改导出对象,只要写module.exports,最后导出的都是module.exports的值
        3. exports是对module.exports的初始引用,仅为了方便给导出的对象添加属性,所以不能使用exports = value的形式导出数据,但是可以使用module.exports === xxxx 导出数据
        4. 在使用exports,this,module.exports的方式修改数据的时候,其指向的对象已经不再是同一个了。(具体原理待研究)
        5. 浏览器端运行
        • 浏览器端需要编译,步骤如下
          1. 全局安装browserify: npm i browserify -g
          2. 编译 browserify index.js -o build.js (index.js是源文件,build.js是输出的目标文件)
          3. 页面中引入使用
      • 扩展
        • 一个js模块在执行时,是被包裹在一个内置函数中执行的,所以每个模块都有自己的作用域,我们可以通过如下方式验证这一说法:
        console.log(arguments.callee.toString())
        
        • 内置函数的大概形式如下
        function (exports, require, module, __filename, __dirname){/*****/}
        
    • 导入
      • const obj = require('export.js的文件路径')
      • const { name } = require('export.js的文件路径') // 对象解构赋值
      • const { name: reName } = require('export.js的文件路径') // 变量重命名
  • AMD
    • 环境配置:
      • 文件目录
        - js
          - main.js
          - file1.js
          - file2.js
        - libs
          require.js
        -index.html
        
      • 文件说明
        • js文件夹中存放业务逻辑代码,main.js用于汇总各模块
        • libs中存放的是第三方库,例如必须要用的require.js
      • 下载require.js,在index.html中配置main.js与require.js
      // index.html
      <script data-main="./js/main.js" src="./js/libs/require.js"></script>
      
      • 在main.js中编写模块配置对象,注册所有模块,内容为
      requirejs.config({
        // 基本路径
        baseUrl: './js',
        // 模块标识名与模块路径映射
        paths: {
          file1: "file1",
          file2: "file2",
        }
      })
      
    • 导出:调用require.js中的内置函数define(),参数为函数,函数内部为正常代码,需要在最后位置将需要导出的变量进行return导出。
      define(function() {
        /**正常代码部分*/
        return xxx; // 返回值部分,类型不限
      })
      
    • 导入:调用define函数,第一个参数传入一个数组,数组里边写上对应的文件模块映射的字符串
      define(["file1"], function(f){
        f.doSomething();
        /**正常代码部分*/
        return xxx;
      })
      
  • CMD
    1. 目录结构
    - sea-modules // 存放seajs,jquery等文件,这也是模块的部署目录
    - static  // 存放各个项目的js,css文件
      - todo
    - app // 存放html文件
      - todo.html
    
    1. 环境准备
    • 使用sea.js
    <!-- html文件 在页尾引入sea.js -->
    <script src="path/to/sea.js"></script>
    <!-- 在下面写模块的配置和入口 -->
    <script>
      // sea.js简单配置
      seajs.config({
        base: '../sea-modules/',
        alias: {
          'jquery', '../xx/xx/jquery.js',
        }
      })
      // 加载入口模块 内容为main的入口文件的路径
      seajs.use("../xxx/xxx/main.js")
    </script>
    
    1. 导出数据
    // math.js文件
    define(function(require, exports, module) {
      // exports的方式导出接口
      exports.add = function(a, b) {
        return a + b;
      };
      // 还可以使用module.exports的方式导出整个接口
      // module.exports = {...}
    });
    
    1. 导入数据
    // math.js文件
    define(function(require, exports, module) {
      const xxx = require('math.js') // 通过require的方式引入依赖
      require.async('./b', function(b) { // 通过require.async异步加载一个模块,在加载完成后执行回调
        b.doSomething();
      })
      require.async(['./c', './d'], function(c, d) { // 通过require.async异步加载多个模块,在加载完成后执行回调
        c.doSomething();
        d.doSomething();
      })
    });
    
    1. 使用模块文件
      // main.js文件 加载一个模块
      seajs.use('math.js', function(math) {
        const sum = math.add(1, 2);
        console.log(sum); // 输出3
      });
      // 加载多个模块
      seajs.use(['./a', './b'], function(a,b){
        a.doSometing();
        b.doSometing();
      })
    
  • ES模块化:客户端应用广泛
    • ES6模块化规范是一个官方标准的规范,它是在语言标准的层面上实现了模块化规范,是目前最流行的模块化规范,且浏览器与服务端均支持该规范
    • 在客户端中运行
      • 用服务器跑html文件,html文件引入模块化部分文件是使用
    • 在node中运行
      1. 将js文件后缀设置为mjs
      2. 配置package.json文件,里边必须将type设置为module
    • 导出
      1. 分别导出:使用多个export进行导出,export 后边跟语句
      2. 统一导出:使用export {} 导出, {}不是对象,是包含统一导出内容的块
      3. 默认导出:使用 export default,写法为: export default 值
      • 备注:上述导出方式可以同时使用
    • 导入
      • 全部导入 import * as esModule from '${filepath}' // 适用于分别导出和统一导出 esModule为自定义常量名
      • 命名导入 import { name } from '${filepath}'
      • 默认导入 import defaultName from '${filepath}'
      • 动态导入:在代码中使用 import('${filepath}') 进行导入,结果为一个promise,可以使用.then链式调用或者asyns,await获取结果
      • import 不接受任何数据 import '${filepath}' // 例如: import 'index.css'; import 'myJs.js'
      • 注意:命名导入和默认导入可以混合使用

posted on 2024-11-29 12:02  shenhf  阅读(95)  评论(0)    收藏  举报

导航