ES6专题—class与模块化(10)
JavaScript语言自创立之初,一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。很多编程语言都有这项功能,比如 Python的import、Ruby的require,甚至就连CSS都有@import,但是JavaScript没有这方面的支持,这增加了开发大型的、复杂的项目时的难度。
于是前端开发者们开始想办法,为了防止命名空间被污染,采用的是命名空间的方式。
在ES6之前,一些前端社区制定了模块载入方案,最主要的有CommonJS和AMD两种。前者用于伺服器,后者用于浏览器。
但这两种规范都由开源社区制定,没有统一,而ES6中引入了模块(Module)体系,从语言层在实现了模块机制,实现了模块功能,而且实现得相当简单,为JavaScript开发大型的、复杂的项目扫清了障碍。
ES6中的模块功能主要由两个命令构成:export和import。
export命令用于规定模块的对外介面,import命令用于输入其他模块提供的功能,二者属于相辅相成、一一对应关系。
一、什么是模块
模块可以理解为函数代码块的功能,是封装对象的属性和方法的javascript代码,它可以是某单个文件、变数或者函数。
模块实质上是对业务逻辑分离实现低耦合高内聚,也便于代码管理而不是所有功能代码堆叠在一起,模块真正的魔力所在是仅导出和导入你需要的绑定,而不是将所有的东西都放到一个文件。
在理想状态下我们只需要完成自己部分的核心业务逻辑代码,其他方面的依赖可以通过直接载入被人已经写好模块进行使用即可。
二、export 导出 命令
一个模块就是一个独立的文件,该文件内部的所有变数,外部无法获取。如果想从外部能够读取模块内部的某个变数,就必须使用export关键字输出该变数。分为以下几种情况:
(1)在需要导出的lib.js文件中, 使用 export{介面} 导出介面, 大括弧中的介面名字为上面定义的变数, import和引入的main.js文件中的export是对应的:
//lib.js 文件
let bar = "stringBar";
let foo = "stringFoo";
let fn0 = function() {
console.log("fn0");
};
let fn1 = function() {
console.log("fn1");
};
export{ bar , foo, fn0, fn1}
//main.js文件
import {bar,foo, fn0, fn1} from "./lib";
console.log(bar+"_"+foo);
fn0();
fn1();
(2)在export介面的时候, 我们可以使用 XX as YY, 把导出的介面名字改了, 比如: xiaoming as haoren,
这样做的目的是为了让介面栏位更加语义化。
//lib.js文件
let fn0 = function() {
console.log("fn0");
};
let obj0 = {}
export { fn0 as foo, obj0 as bar};
//main.js文件
import {foo, bar} from "./lib";
foo();
console.log(bar);
(3)直接在export的地方定义导出的函数,或者变数:
//lib.js文件
export let foo = ()=> {console.log("fnFoo") ;return "foo"},bar = "stringBar";
//main.js文件
import {foo, bar} from "./lib";
console.log(foo());
console.log(bar);
(4)不需要知道变数名字(相当于是匿名的)的情况,可以 直接把开发的介面给export。如果一个js模块文件就只有一个功能, 那么就可以使用export default导出。
//lib.js
export default "string";
//main.js
import defaultString from "./lib";
console.log(defaultString);
这样做的好处是其他模块载入该模块时,import命令可以为该匿名函数指定任意名字。
(5)export也能默认导出函数, 在import的时候, 名字可以自定义, 因为每一个模块的默认介面就一个:
//lib.js
let fn = () => "string";
export {fn as default};
//main.js
import defaultFn from "./lib";
console.log(defaultFn());
(6)使用通配符* ,重新导出其他模块的介面
//lib.js
export * from "./other";
//如果只想导出部分介面, 只要把介面名字列出来
//export {foo,fnFoo} from "./other";
//other.js
export let foo = "stringFoo", fnFoo = function() {console.log("fnFoo")};
//main.js
import {foo, fnFoo} from "./lib";
console.log(foo);
console.log(fnFoo());
三、import 导入 命令
ES6导入的模块都是属于引用,每一个导入的js模块都是活的, 每一次访问该模块的变数或者函数都是最新的, 这个是原生ES6模块 与AMD和CMD的区别之一。
使用export命令定义了模块的对外介面以后,其他 JS 文件就可以通过import命令载入这个模块。
//main.js文件
import {bar,foo, fn0, fn1} from "./lib";
console.log(bar+"_"+foo);
fn0();
fn1();
大括弧里面的变数名,必须与被导入模块对外介面的名称相同。
想要输入的变数重新取一个名字,import命令要使用 as关键字,将输入的变数重命名。
import { formatFn as fn0 } from lib.js;
注:import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js后缀可以省略。