# js模块化设计

# 模块设计

项目变大时需要把不同的业务分割成多个文件,这就是模块的思想。模块是比对象与函数更大的单元,使用模块组织程序便于维护与扩展。

  • 模块就是一个独立的文件,里面是函数或者类库
  • 虽然JS没有命名空间的概念,使用模块可以解决全局变量冲突
  • 模块需要隐藏内部实现,只对外开发接口
  • 模块可以避免滥用全局变量,造成代码不可控
  • 模块可以被不同的应用使用,提高编码效率

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

// CommonJS模块
下面的这种加载称为"运行时加载",因为只有运行时才能得到这个对象,导致完全没办法在编译时做"静态优化"let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

==ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。==

// ES6模块
该种方式属于"编译时加载"(静态加载),即是在编译的时候就完成模块的加载。效率比CommonJs高。
import { stat, exists, readFile } from 'fs';

# 基础知识

# 标签使用

在html文件中导入模块,需要定义属性 type="module"

# 模块路径

在浏览器中引用模块必须添加路径如./ ,但在打包工具如webpack中则不需要,因为他们有自己的存放方式。

test.js 模块如下

export let test = {
  name: "this is a test module"
};

在html里面引入并使用

<script type="module">
  import { test } from "./test.js";
  console.log(test.name) // this is a test module
</script>

# 延迟解析

模块总是会在所有html解析后才执行

建议为用户提供加载动画提示,当模块运行时再去掉动画

# 严格模式

模块默认运行在严格模式

变量必须先声明才使用

# 作用域

// 模块都有独立的顶级作用域,下面的模块不能互相访问

<script type="module">
  let mo1 = "module1";
</script>

<script type="module">
 console.log(mo1)
</script>

// 单独文件作用域也是独立的

# 预解析

模块在导入时只执行一次解析,之后的导入不会再执行模块代码,而使用第一次解析结果,并共享数据。

  • 可以在首次导入时完成一些初始化工作
  • 如果模块内有后台请求,也只执行一次即可

# 模块的导入导出

  • 使用export 将开发的接口导出
  • 使用import 导入模块接口
  • 使用*可以导入全部模块接口
  • 导出是以引用方式导出,无论是标量还是对象,即模块内部变量发生变化将影响已经导入的变量

# 导出模块

使用 export 导出模块接口,没有导出的变量都是模块私有的。

jc.js模块 分别导出 常量,方法,类

const host = "www.baidu.com";

function sum(a,b){
  return a+b;
}

class User {
  show() {
    console.log("user.show function");
  }
}

export {host,sum, User};
[具名导出]

# 别名导出

模块可以对导出给外部的功能起别名

export {host as Host, sum as Add, User};
// 使用别名导入
<script type="module">
  import { Host, Add, User } from "./jc.js";
  action();
</script>

# 默认导出

很多时候模块只是一个类,也就是说只需要导入个内容,这里可以使用默认导出。

使用default 定义默认导出的接口,导入时不需要使用 {}

  • 可以为默认导出自定义别名
  • 只能有一个默认导出
  • 默认导出可以没有命名
export { User as default };

// 导入使用 [ 默认导出不需要{} import ]
import User from "./hd.js";
let user = new User()   
console.log(user.show() )

# 混合导出

模块可以存在默认导出与命名导出。 使用export default 导出默认接口,使用 export {} 导出普通接口

const site = "www.jc-sir.github.io";
const func = function() {
  console.log("this function in jc.module");
};
export default class {
  static show() {
    console.log("user.show");
  }
}
export { site, func };

// 也可以如下导出
const site = "www.jc-sir.github.io";
const func = function() {
  console.log("this function in jc.module");
};
 class User{
  static show() {
    console.log("user.show");
  }
}
export { site, func ,User as default};

// 导入默认接口时不需要使用 {} ,普通接口还用 {} 导入

<script type="module">
	//可以将 jc 替换为任何变量
  import jc from "./jc.js";  // jc指向默认导出
  import { site } from "./jc.js";
  console.log(site);
  jc.show();
</script>

可以使用一条语句导入默认接口与常规接口

import jc, { site } from "./jc.js";

也可以使用别名导入默认导出

import { site ,default as jc } from "./jc.js";
console.log(site);
jc.show();

如果是批量导入时,使用 default 获得默认导出

<script type="module">
  import * as api from "./jc.js";
  console.log(api.site);
  api.default.show();
</script>

# 使用建议

对于默认导出和命名导出有以下建议

  • 不建议使用默认导出,会让开发者导入时随意命名
  • 如果使用默认导入最好以模块的文件名有关联,会使用代码更易阅读

# 具名导入

在html 里面导入并使用

<script type="module">
// [具名导入]
    import  {host,sum, User}  from "./jc.js";
    console.log(host);
    console.log(sum(5,10));
    let user = new User();
    user.show();
</script>

# 别名导入

可以为导入的模块重新命名

  • 有些导出的模块命名过长,起别名可以理简洁
  • 本模块与导入模块重名时,可以通过起别名防止错误
<script type="module">
// [导入别名]
    import { host as Host, sum as Add, User } from "./jc.js";
    console.log(Host);
    console.log(Add(5, 10));
    let user = new User();
    user.show();
</script>

# 批量导入

如果要导入的内容比较多,可以使用* 来批量导入。

<script type="module">
    import * as api from "./jc.js";
    console.log(api.host);
    console.log(api.sum(5, 10));
    let user = new api.User();
    user.show();
</script>

# 导入建议

更建议使用明确导入方式

  • 使用webpack 构建工具时,没有导入的功能会删除节省文件大小
  • 可以更清晰知道都使用了其他模块的哪些功能
  • 模块默认是在顶层静态导入,这是为了分析使用的模块方便打包

# 总结

表达式 说明
export var name="J_xiaozuo" 导出变量
export function show(){} 导出函数
export class user{} 导出类
export {name as jc_name} 别名导出
import defaultVar from 'jc.js' 导入默认导出
import {name,show} from 'jc.js' 导入命名导出
import {name as jcName,show} from 'jc.js' 别名导入
import * as api from 'jc.js' 导入全部接口
Last Updated: 10/31/2022, 9:57:48 PM