JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require、Python 的import,甚至就连css 都有@import,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
两个命令 expont 和 import
expont 命令用于规定模块的对外接口
import命令用于输入其他模块提供的功能
expont:
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量
下面是一个 JS 文件,里面使用export命令输出变量。
// profile.js
export var firstName = 'Michael';
export var lastName ='Jackson';
export var year=1958;
import
使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。
export default 命令
export default命令,为模块指定默认输出。
// export-default .js
export default function(){console.log('foo');}
以上默认输出一个函数
export default命令用在非匿名函数前,也是可以的
// export-default .js
export default function foo(){console.log('foo');}
// 或者写成 function foo(){console.log('foo');}export default foo;
上面代码中,foo函数的函数名foo,在模块外部是无效的。加载的时候,视同匿名函数加载。
export 与 import 的复合写法
如果在一个模块之中,先输入后输出同一个模块,import语句可以与export语句写在一起。
export {foo,bar} from 'my_module';
// 等同于 import {foo,bar} from 'my_module';
export {foo,bar};
import()的用法及场景
import命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行(叫做”连接“更合适)。
// 报错if(x===2){
import MyModual from './myModual';
}
上面代码中,引擎处理import语句是在编译时,这时不会去分析或执行if语句,所以import语句放在if代码块之中毫无意义,因此会报句法错误,而不是执行时错误。也就是说,import和export命令只能在模块的顶层,不能在代码块之中(比如,在if代码块之中,或在函数之中)。
这样的设计,固然有利于编译器提高效率,但也导致无法在运行时加载模块。在语法上,条件加载就不可能实现。如果import命令要取代 Node 的require方法,这就形成了一个障碍。因为require是运行时加载模块,import命令无法取代require的动态加载功能。
const path='./'+ fileName;
const myModual=require(path);
上面的语句就是动态加载,require到底加载哪一个模块,只有运行时才知道。import语句做不到这一点。
import()返回一个 Promise 对象
const main=document.querySelector('main');
import(`./section-modules/${someVariable}.js`)
.then(module=>{module.loadPageInto(main);})
.catch(err=>{main.textContent=err.message;});
import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,也会加载指定的模块。另外,import()函数与所加载的模块没有静态连接关系,这点也是与import语句不相同。
import()类似于 Node 的require方法,区别主要是前者是异步加载,后者是同步加载。
场景:
1)按需加载。
import()可以在需要的时候,再加载某个模块。
(2)条件加载
import()可以放在if代码块,根据不同的情况,加载不同的模块
(3)动态的模块路径
import()允许模块路径动态生成。