什么是模块
模块是自动运行在严格模式下并且没有办法退出运行的 JavaScript 代码。
在模块顶部创建的变量不会自动被添加到全局变量作用域,这个变量仅在模块的*作用域中存在,而且模块必须导出一些外部代码可以访问的元素。
模块也可以从其他模块导入绑定。
在模块的顶部,this 的值是
undefined。
模块不支持 HTML 风格的代码注释。
导出基本语法
用export关键字将一部分已发布的代码暴露给其他模块
//导出数据
export var color = "red";
export let name = "JiaJia";
export const magicNumber =7
//导出函数
export function sum(num1,num2){
return num1+num2;
}
//导出类
export class Rectangle{
constructor(length,width){
this.length=length;
this.width=width;
}
}
//this is private function
function subtract (num1 ,num2){
return num1 - num2;
}
//define a function
function multiply (num1,num2)
return num1*num2;
}
//export it
export muitply;
导入的基本语法
通过 import 关键字导入在另一个模块中导出的功能。
import { identifier1,identifier2 } from "./example.js"
import 后面的大括号表示从给定模块导入的绑定(binding),关键字 from 表示从哪个模块导入给定的绑定。
当从模块中导入一个绑定时,它就好像使用 const 定义的一样。结果是你无法定义另一个同名变量(包括导入另一个同名绑定),也无法在
import 语句前使用标识符或改变绑定的值。
导入单个绑定
import {sum} from "./example.js";
console.log(sum(1,2));//3
//抛出错误
sum =1;
导入多个绑定
import { sum, multiply,magicNumber}
from
"./example.js"
console.log(sum(1,magicNumber));//8
console.log(multiply(1,2));//2
导入整个模块
//命名空间导入
import * as example from "./example.js";
console.log(example.sum(1,example.magicNumber));//8
console.log(example.multiply(1,2));//2
不管在 import 语句中把一个模块导入了多少次,该模块只执行一次。
如果同一个应用程序中的其他模块也从 example.js 导入绑定,那么这些模块与此代码将使用相同的模块实例。
导入绑定的一个微妙怪异之处
export var name = "JiaJia";
export function setName(newName){
name = newName;
}
import { name ,setName (newName){
name = newName;
}
import{ name,setName} from "./example.js";
console .log(name);//"JiaJia";
setNmae("l");
console.log(name);//"l"
name = "JiaJia";//抛出错误
导出和导入时重命名
function sum(num1,num2){
return num1 + num2;
}
export{
sum as add
};
import {add as sum} from "./example.js";
模块的默认值
模块的默认值指的是通过default关键字指定的单个变量 ,函数或类,只能为每个模块设置一个默认的导出值.
export defult function (num1,num2){
return num1 + num 2;
}
等同于
function sum (num1 ,num2){
return num1 +num2;
}
export default sum;
等同于
function sum (num1,num2){
return num1+num2;
}
export { sum as default };
导入默认值
import sum from "./example.js";
console.log(sum(1,2));//3
导入默认值和以外的值:
import sum,{color }from "./example.js";
或者
import {default as sum,color}from "./example.js";
重新导出一个绑定
import{sum}from "./example.js";
export {sum}
或者简写如下模式:
export {sum}from "./example.js";
导出一切:
export * from "./example.js";
无绑定导入
///没有export 或import 的模块代码
Array.prototype.pushAll =function(items){
if (!Array.isArray(items)){
throw new TypeError("参数必须是一个数组");
}
return this.push(...items);
}
import "./example.js"
加载模块
在Web浏览器中使用模块
- 在
<script>
元素中通过src属性指定一个加载代码的地址来加载 JavaScript 代码文件 - 将 JavaScript 代码内嵌到没有 src 属性的
<script>
元素中 - 通过 Web Worker 或 Service Worker 的方法加载并执行 JavaScript 代码文件
在<Script>
中使用模块
<!-- 加载一个 JavaScript 模块文件 -->
<script type="model" src="module.js"></script>
<!-- 内联引入一个模块 -->
<script type="model">
import {sum} from "./example.js";
let result =sum (1,2);
</script>
Web浏览器中的模块加载顺序
模块按照它们出现在HTML文件中的顺序执行,也就是说,无论模块中包含的是内联代码还是指定的src属性,第一个<script type="module">总是在第二个之前执行.
Web浏览器中的模块加载顺序
当应用async属性时,脚本文件将在文件完全下载并解析后执行.脚本在文档中的顺序不会影响脚本的执行顺序.
<!-- 无法保证这两个谁先执行 -->
<script type="module" asnyc src="module1.js"></script>
<script type="module" asnyc src="module2.js"></script>
将模块作为 Worker 加载
Worker,例如 Web Worker 和 Service Worker,可以在网页上下文之外执行 JavaScript 代码。
// 默认按照脚本的方式加载 script.js
let worker = new worker("script.js");
//默认按照模块的方式加载 script.js
let worker = new Worker("script.js",{type:"module"});
浏览器模块说明符解析
浏览器要求模块说明符具有以下几种格式之一:
- 以/开头的解析为从根目录开始
- 以./开头的解析为从当前目录开始
- 以../开头的解析为从父目录开始
- 以URL格式
//从https://www.example.com/modules/example1.js导入
import {first}from "./example1.js"
//从https://www.example.com/example2.js导入
import {second}from "./example1.js";
//从https://www.example.com/example3.js导入
import {third}from "./example3.js"
//从https://www.example.com/example4.js导入
import {fourt}from "./example4.js"
"http://www.example.com/example4.js";