JavaScript模块基本用法

模块的概念

一个模块就是一个文件,一个脚本就是一个模块

模块可以相互加载,使用特殊的指令 exportimport 就可以实现交换功能,从另一个模块调用一个模块的函数:

  • export 关键字标记了可以从当前模块外部访问的变量和函数。
  • import 关键字允许从其他模块导入功能。

例如有一个exprot.js文件导出一个函数

export function sayHi(user) {
  alert(`Hello, ${user}!`);
}

然后另一个文件导入这个函式

import {sayHi} from './export.js';

alert(sayHi); // function...
sayHi('John'); // Hello, John!

import 指令通过相对于当前文件的路径 ./export.js 加载模块,并将导入的函数 sayHi 分配给相应的变量。

在使用模块时,必须通过使用 <script type="module">告诉浏览器此脚本要当作模块来使用

<script type="module">
  import {sayHi} from './export.js';

  document.body.innerHTML = sayHi('John');
</script>

// 页面输出 Hello, John!

模块核心功能

始终使用"use strict"

模块始终默认使用 use strict,如果对一个未声明的变量赋值将报错

<script type="module">
  a = 5; // error
</script>

模块级作用域

每个模块都有自己的作用域,一个模块中的顶级作用域变量和函数在其他脚本中不可使用

user.js

let user = "John";

hello.js

alert(user)

index.html

<script type="module" src="user.js"></script>
<script type="module" src="hello.js"></script>

上述三个代码,hello.js 尝试使用在 user.js 中声明的变量 user,报错

如果想要访问到user.js中的内容,需要export 想要被外部访问的内容,并 import 它们所需要的内容

user.js

export let user = "John";

hello.js

import {user} from './user.js';

document.body.innerHTML = user; // John

在浏览器中,每个模块也有自己的独立作用域

<script type="module">
  // 变量仅在这个 module script 内可见
  let user = "John";
</script>

<script type="module">
  alert(user); // Error
</script>

模块代码仅在第一次被导入时解析

如果同一个模块被导入到多个其他位置,那么它的代码仅会在第一次导入时执行,讲导出的内容提供给所有的导入

// 📁 alert.js
alert("Hello World!");
// 在不同的文件中导入相同的模块

// 📁 1.js
import `./alert.js`; // Hello World!

// 📁 2.js
import `./alert.js`; // (什么都不显示)

如果一个模块导出一个对象

// 📁 admin.js
export let admin = {
  name: "John"
};

这个模块被导入多个文件中,模块仅在第一次被导入时解析,并创建admin对象,然后传入到所有的导入中

// 📁 1.js
import {admin} from './admin.js';
admin.name = "Pete";

// 📁 2.js
import {admin} from './admin.js';
alert(admin.name); // Pete

1.js2.js 导入的是同一个对象,在 1.js 中对对象做的更改,在 2.js 中也是可见的

我们就可以在首次导入模块时对其进行设置,我们只需设置其属性,然后在进一步导入中可以直接使用

export let admin = { };

export function sayHi() {
  alert(`Ready to serve, ${admin.name}!`);
}

1.js中设置了 admin.name,现在每个位置都能看到它,包括在 admin.js 内部的调用

// 📁 1.js
import {admin} from './admin.js';
admin.name = "Pete";

2.js中也可以看到 admin.name

// 📁 2.js
import {admin, sayHi} from './admin.js';

alert(admin.name); // Pete

sayHi(); // Ready to serve, Pete!

import.meta

import.meta 对象包含关于当前模块的信息。

<script type="module">
  alert(import.meta.url); // 脚本的 URL,如果是内嵌脚本,则是当前HTML页面的URL
</script>

在模块中,"this"是 undefined

<script type="module">
  alert(this); // undefined
</script>

浏览器特定功能

拥有 type="module" 标识的脚本有一些特定于浏览器的差异

脚本模块是延时的

模块脚本 总是 被延迟执行,与defer特性的影响相同

  • 下载外部模块脚本 <script type="module" src="..."> 不会阻塞 HTML 的处理,它们会与其他资源并行加载。
  • 模块脚本会等到 HTML 文档完全准备就绪,然后才会运行。
  • 会保持脚本的相对顺序:在文档中排在前面的脚本先执行。

一个副作用是,模块脚本总是会看到已经加载完的HTML页面,包括在它下面的HTML元素

<script type="module">
  alert(typeof button); // object:脚本可以发现下面的 button
  // 因为模块是被延迟的 所以模块脚本会在整个页面加载完成后才运行
</script>


// 常规脚本
<script>
  alert(typeof button); // Error: button is undefined,脚本看不到下面的元素
  // 常规脚本会立即运行,常规脚本的运行是在在处理页面的其余部分之前进行的
</script>

<button id="button">Button</button>

不允许裸模块

在浏览器中,import 必须给出相对或绝对的 URL 路径。没有任何路径的模块被称为“裸(bare)”模块。在 import 中不允许这种模块。

import {sayHi} from 'sayHi'; // Error,裸模块

在Node.js或者打包工具中允许没有任何路径的裸模块,但是浏览器不支持

兼容性 nomodule

旧版本的浏览器不支持type="module",可以使用 nomodule 特性来提供一个后备:

<script nomodule>
	 alert(" is nomodule ");
</script>

总结

  1. 一个模块就是一个文件。浏览器需要使用<script type="module">使import/export 可以工作
  2. 模块和常规的脚本差别
    • 默认是延迟解析的
    • 重复的外部脚本会被忽略
  3. 模块具有自己的本地顶级作用域,并可以通过 import/export 交换功能。
  4. 模块始终使用 use strict
  5. 模块代码只执行一次。导出仅创建一次,然后会在导入之间共享
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值