JavaScript语言自创立之初,一直没有模块(module)体系,没法将一个大程序拆分红互相依赖的小文件,再用简单的方法拼装起来。javascript
不少编程语言都有这项功能,好比 Python的import、Ruby的require,甚至就连CSS都有@import,可是JavaScript没有这方面的支持,这增长了开发大型的、复杂的项目时的难度。前端
因而前端开发者们开始想办法,为了防止命名空间被污染,采用的是命名空间的方式。vue
在ES6以前,一些前端社区制定了模块加载方案,最主要的有CommonJS和AMD两种。前者用于服务器,后者用于浏览器。java
但这两种规范都由开源社区制定,没有统一,而ES6中引入了模块(Module)体系,从语言层在实现了模块机制,实现了模块功能,并且实现得至关简单,为JavaScript开发大型的、复杂的项目扫清了障碍。react
ES6中的模块功能主要由两个命令构成:export和import。webpack
export命令用于规定模块的对外接口,import命令用于输入其余模块提供的功能,两者属于相辅相成、一一对应关系。web
1、什么是模块编程
模块能够理解为函数代码块的功能,是封装对象的属性和方法的javascript代码,它能够是某单个文件、变量或者函数。浏览器
模块实质上是对业务逻辑分离实现低耦合高内聚,也便于代码管理而不是全部功能代码堆叠在一块儿,模块真正的魔力所在是仅导出和导入你须要的绑定,而不是将全部的东西都放到一个文件。服务器
在理想状态下咱们只须要完成本身部分的核心业务逻辑代码,其余方面的依赖能够经过直接加载被人已经写好模块进行使用便可。
2、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());
3、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后缀能够省略。
4、ES6模块化的基本规则、特色
一、每个模块只加载一次, 每个JS只执行一次, 若是下次再去加载同目录下同文件,直接从内存中读取。 一个模块就是一个单例,或者说就是一个对象。
二、每个模块内声明的变量都是局部变量, 不会污染全局做用域。
三、模块内部的变量或者函数能够经过export导出。
四、一个模块能够导入别的模块。
5、class与模块化相结合实例
结合上节课咱们学的 ES6 class与面向对象编程的知识,咱们再实现一个把class和模块化结合的例子。
首先咱们建立一个parent.js文件,使用class类的写法建立一个Parent类:
const name = "tom"; const age = "20"; class Parent{ hw(){ console.log(`hello world`) } static obj(){ console.log('obj')/*表示为静态方法不回呗实例继承,而是直接经过类调用。*/ } } var parent = new Parent() parent.hw()//hell world export{name,age,Parent}
以后在child.js中分别引入parent.js中的name、age、Parent
import {name,age,Parent} from './parent' class Child extends Parent{ constructor(obj){ //就是new命令自动跳用方法。一个类必需要有constructor,若是没定义,有默认添加一个空的。 super()//调用父类的constructor() this._config = obj; console.log(obj.name+"年龄"+obj.age) } hw(){ console.log("hw") } set val(value){ this._config.name = value; console.log(`name=${value}`) } get val(){ console.log(this._config.name); } } Child.obj()//obj 继承父类static方法 var model = new Child({name,age}) //tom年龄20 model.hw()//hw model.val = "jock"; //name=jock model.val//jock
6、总结
本文主要从什么是模块,模块的导出(导出变量、函数、类、文件等),模块的导入(单个导入、多个导入、导入整个)等角度讲述了ES6模块化操做。
ES6模块的设计思想,是尽可能的静态化,使得编译时就能肯定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时肯定这些东西。好比 CommonJS模块就是对象,输入时必须查找对象属性。
模块打包如今最好用的就是webpack了,webpack做为一款新兴的模块化管理和打包工具,其视任意文件都为模块,并打包成bundle文件,相比于browserify更增强大。
模块化开发是前端开发的一大趋势,好比你们去看vue、react、angular,或者大家公司的项目源码,你会发现,几乎全部项目都使用了模块化。小伙伴们必定要紧跟时代的大潮,将组件化开发,模块化开发,自动化构建结合,探索高效的开发之道。