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,或者大家公司的項目源碼,你會發現,幾乎全部項目都使用了模塊化。小夥伴們必定要緊跟時代的大潮,將組件化開發,模塊化開發,自動化構建結合,探索高效的開發之道。