JS模块化开发的学习

模块化是一种项目的构架模式, 这种构架模式让JS代码重用性变得非常高,让项目构架的一些复杂问题全部得以解决。 例如,多个script标签不会再出现了,我们只要用一个script标签进行引入就可以了。

为了减少系统耦合度,提高内聚,减少资源依赖
便于维护,功能复用性更强
解决独立作用域、依赖管理、api暴露、按需加载与执行、安全合并等问题

如何模块化

  • 封装之后的入口和出口
  • 获取模块

模块化的规范 - 引入模块和定义模块的方式

  • AMD:第三方规范
    • 依赖前置的加载方式
    • 规范化文件是:require.js
    • 定义
    • 引入
  • CMD:第三方规范,已经被抛弃了
    • 按需加载的方式
    • 规范化文件是:sea.js
  • CommonJs:后端的模块化规范:node官方的模块化规范
    • 依赖前置的加载方式
    • 引入:const 模块对象 = require(“模块名”)
    • 定义:
  • ES6:ECMAScript的官方推出的模块化规范
    • 依赖前置的加载方式
    • 定义
    • 引入

require.js的使用(AMD第三方规范)

  • 基本语法

    • require(参数1,参数2)

      • 参数1:数组,数组内放置要引入的模块的路径
      • 参数2:回调函数,表示所有的模块引入完成后,才会执行的功能
        • 回调函数的形参和引入的模块一一对应,表示引入模块的出口
      • 引入模块,可以在一个文件内出现多次,因为可能会存在,引入不同批次的模块,实现不同的功能
    • define(参数1,参数2)

      • 参数1:数组,数组内放置定义本模块时,要依赖的其他模块的路径,可选
      • 参数2:回调函数,表示要定义的模块的功能,会在所有的模块引入完成后,才会执行
        • 回调函数的形参和引入的依赖模块一一对应,表示引入模块的出口
      • 定义模块一般为一个独立的js文件,一个js文件内,只有一个define(参数1,参数2)函数
  • 简单使用

    • 在小模块中只定义功能,不执行,暴露到外部,在外部执行(jq必须加载完毕)
  • 高级使用

    • main文件的概念
      • 如果使用独立的script标签的src引入main文件,此时main文件中的小模块的路径起始点,以当前html文件开始
      • 如果使用引入了require.js的script标签的data-main属性,引入main文件,此时main文件中的小模块的路径起始点,以main文件开始
    • 路径的配置
      • 提前配置路径的起始点
      • 设置基路径
      • 给小模块起别名
// 可以提前配置路径的起始点
require.config({
    // 设置基路径
    baseUrl:"./modules",
    // 给小模块起别名
    paths:{
        rc: "randomColor",
        jq: "https://lib.baomitu.com/jquery/3.6.0/jquery"
    }
})

require(["rc","jq"], function(rc){
    console.log(rc);
    console.log($);
})
  • 模块之间的引入和执行顺序
    • 引入:不分顺序
    • 执行:异步执行
    • 所有的回调函数,是同步执行
    • 在主模块的回调函数中执行小模块的功能,在小模块的功能中可以使用其他模块的任意全局变量
require.config({
    baseUrl:"./modules",
    paths:{
        abc: "jq_test",
        jq: "https://lib.baomitu.com/jquery/3.6.0/jquery"
    }
})

// require中的回调函数里的_是占位符,为了使用回调函数后面的参数,因为参数是一一对应的,依赖前置
require(["jq","abc"], function(_, abc){
    console.log("小模块全部加载完毕");

    // 在主模块的回调函数中执行小模块的功能,在小模块的功能中可以使用其他模块的任意全局变量
    abc();

    console.log($);
})

总结

  • 功能单独写到js文件中,使用define包装
  • 使用require函数引入使用define包装之后的js文件

ES6模块化

ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

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

ES6模块的使用:
使用export规定模块的对外接口,使用import用于输入其他模块提供的功能

语法

定义模块export语法:(module.js文件)

export var a = 10;

var b = 20;
export {b};

var c = "admin"
export {c as name};

// 上面的写法等同于下面的写法

export {a,b,c};
export {a as num1, b as num2, c as name};
export default {num1:a, num2:b, name:c}

加载模块import语法:(main.js文件)

import {a} from "./module.js";
import {b} from "./module.js";
import {c} from "./module.js";
import {a,b,c} from "./module.js";
import {num1,num2,num3} from "./module.js”;
// 上面的写法等同于下面的写法
import {num1 as n1, num2 as n2, num3 as n3} from "./module.js";
import obj from "./module.js";

注意点

1.export和import关键字,只能存在于顶层作用域内,不能存在局部或块级作用域
2.在ES6的模块化中,所有语法自动处在严格模式下
3.export是声明关键字,声明一个对外接口
4.export声明的接口必须和模块内部的变量建立一一对应的关系
5.export声明的接口与对应的值是动态绑定,即可以拿到模块内部实时修改的值
5.export和import时,都可以使用as关键字,重命名接口
6.使用default关键字,设置默认接口,一个模块中只允许出现一次default
7.import在使用接口时,必须将接口放在花括号内,除非export暴露接口时使用了default关键字
8.import加载的接口是只读的,不允许被修改,如果接口是对象,可以修改属性
9.import具有提升效果
10.由于import是静态执行,所以不能使用表达式和变量
11.当import后没有接收接口,会执行整个模块文件
12.可以使用通配符*加载整个模块的接口(需要配合as使用),返回一个模块对象
13.ES6的模块化不是对象,而是通过export输出对应的代码,再通过import输入
14.import加载模块的输入接口是静态加载,指定接口的情况下,只加载接口部分
15.ES6的模块化语法比ES6的常规语法的兼容性还要差所以必须要处于服务器环境
16.引入主模块的script标签必须设置type属性,值为module

使用ES6模块化的步骤

  1. 主HTML文件引入主js文件<script src="./js/main.js" type="module"></script>,其中,script标签必须设置type属性,值为module
  2. 主js文件main.js指定引入模块,模块文件中指定输出
  3. 在服务器环境下运行

实例

主index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    正在测试ES6的模块化
</body>
<script src="./js/main.js" type="module"></script>
</html>

主main.js

console.log("主模块被引入")

// 引入了模块a的功能
import {cuihua as alis} from "../modules/hello.js";
console.log(alis);

// 引入的模块值改变主模块的值也会跟着改变
setTimeout(() => {
    console.log(alis);
}, 1000);


import {b, c} from "../modules/hello.js";
console.log(b)
console.log(c)

// import在使用接口时,必须将接口放在花括号内,除非export暴露接口时使用了default关键字
import obj from "../modules/hello.js";
console.log(obj);

// *代表通配符
import * as obj from "../modules/hello.js";
console.log(obj.cuihua)
console.log(obj.b)
console.log(obj.c)

import {d} from "../modules/hello.js";
console.log(d);
// 可以修改对象的属性
d.name = "hahaha"
console.log(d);

import "../modules/world.js";

模块hello.js

var a = 10;
// 暴露了一个a
export {a as cuihua};

setTimeout(() => {
    a = 20;
}, 1000);

var b = "hello world"
export {b};

var c = function(){
    console.log(123123)
}
export {c};

var d = {
    name:"adminb",
    age:189,
    sex:"男"
}
export {d};

// 使用default关键字,设置默认接口,一个模块中只允许出现一次default
export default {a,b,c};

模块world.js

console.log("这是一个炫酷的功能")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值