Module的语法和加载实现

ES6模块提供了静态加载的解决方案,优于CommonJS和AMD,适用于服务器和浏览器。模块通过export导出和import导入,且import的变量为只读。export default允许设置默认导出。浏览器加载模块异步且不阻塞渲染,使用script标签并指定type。模块运行在严格模式下,顶层变量对外部不可见,且关键字如return无效。

1.在es6之前,社区制定了一些模块加载方案,最主要的有CommonJS 和AMD两种。前者用于服务器,后者用于浏览器。es6在语言标准的层面,实现了模块功能,实现简单,完全可以取代CommomJS和AMD模块,成为浏览器与服务器通用的模块解决方案。

es6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommomJS和AMD模块,都只在运行时确定这线东西。

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

除了静态加载带来的各种好处,ES6 模块还有以下好处。

  • 不再需要UMD模块格式了,将来服务器和浏览器都会支持 ES6 模块格式。目前,通过各种工具库,其实已经做到了这一点。
  • 将来浏览器的新 API 就能用模块格式提供,不再必须做成全局变量或者navigator对象的属性。
  • 不再需要对象作为命名空间(比如Math对象),未来这些功能可以通过模块提供。

2.ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";

3.export命令:用于规定模块的对外接口

// 报错
export 1;

// 报错
var m = 1;
export m;

// 写法一
export var m = 1;

// 写法二
var m = 1;
export {m};

// 写法三
var n = 1;
export {n as m};

// 报错
function f() {}
export f;

// 正确
export function f() {};

// 正确
function f() {}
export {f};

4.import命令

使用import命令输入的变量都是只读的

foo();

import { foo } from 'my_module';

上面的代码不会报错,因为import的执行早于foo的调用。这种行为的本质是,import命令是编译阶段执行的,在代码运行之前。由于import是静态执行,所以不能使用表达式和变量(这些是运行时才能得到结果的语法结构)。

5.export default命令

// 第一组
export default function crc32() { // 输出
  // ...
}

import crc32 from 'crc32'; // 输入

// 第二组
export function crc32() { // 输出
  // ...
};

import {crc32} from 'crc32'; // 输入

//上面代码的两组写法,第一组是使用export default时,对应的import语句不需要使用大括号;第二组是不使用export default时,对应的import语句需要使用大括号。

6.浏览器加载

<!-- 执行完脚本,再继续向下执行 -->
<script type="application/javascript" src="path/to/myModule.js">
<!-- 整个页面在内存中正常渲染结束(Dom结果生成,其他脚本执行完成) -->
<script src="path/to/myModule.js" defer></script>
<!-- 一旦下载完,渲染就会中断渲染,执行这个脚本以后,再继续渲染 -->
<script src="path/to/myModule.js" async></script>

一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。

7.浏览器加载模块的规则

浏览器加载 ES6 模块,也使用<script>标签,但是要加入type="module"属性。

<script type="module" src="./foo.js"></script>

浏览器对于带有type="module"<script>,都是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本,等同于打开了<script>标签的defer属性。

ES6 模块也允许内嵌在网页中,语法行为与加载外部脚本完全一致。

<script type="module">
  import utils from "./utils.js";

  // other code
</script>

对于外部的模块脚本(上例是foo.js),有几点需要注意。

  • 代码是在模块作用域之中运行,而不是在全局作用域运行。模块内部的顶层变量,外部不可见。
  • 模块脚本自动采用严格模式,不管有没有声明use strict
  • 模块之中,可以使用import命令加载其他模块(.js后缀不可省略,需要提供绝对 URL 或相对 URL),也可以使用export命令输出对外接口。
  • 模块之中,顶层的this关键字返回undefined,而不是指向window。也就是说,在模块顶层使用this关键字,是无意义的。
  • 同一个模块如果加载多次,将只执行一次。

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值