ES6以前,JS沒有出現模塊化系統。html
JS主要在前端的瀏覽器中使用,js文件下載緩存到客戶端,在瀏覽器中執行。前端
好比簡單的表單本地驗證,漂浮一個廣告。node
服務器端使用ASP、JSP等動態網頁技術,將動態生成數據嵌入一個HTML模板,裏面夾雜着JS後react
使用 <script> 標籤,返回瀏覽器端。es6
這時候的JS只是一些簡單函數和語句的組合。npm
<html> <head> <title>magedu</title> <script src="./src/moda.js"></script> </head> <body> Welcome <script> foo() console.log(CONSTA) </script> </body> </html>
在同一目錄下創建src文件夾,文件夾下創建moda.js文件編程
class A{
constructor(x){
this.x = x
}
show () {
console.log(this.x)
}
}
function foo() {
console.log("foo function");
}
const CONSTA = "aaa"
用瀏覽器打開html文件,在控制檯就能夠看到,瀏覽器下按F12.json
2005年以後,隨着Google大量使用了AJAX技術以後,能夠異步請求服務器端數據,帶來了前端交互的巨大變化。瀏覽器
前端功能需求愈來愈多,代碼也越來也多。隨着js文件的增多,災難性的後果產生了。因爲習慣了隨便寫,js腳本中各類全局變量污染,函數名衝突,沒法表達腳本之間的依賴關係,由於都是用腳本文件前後加載來實現的。亟待模塊化的出現。緩存
2008年V8引擎發佈,2009年誕生了Nodejs,支持服務端JS編程,但沒有模塊化是不能夠的。
以後產生了commonjs規範。
commonjs規範,使用全局require函數導入模塊,使用exports導出變量。
爲了將這種模塊化規範向前端開發遷移,又演化出其它的規範。例如AMD。
AMD(Asynchronous Module Definition)異步模塊定義,使用異步方式加載模塊,模塊的加載不影響它後面語句的執行。全部依賴這個模塊的語句,都須要定義在一個回調函數,回調函數中使用模塊的變量和函數,等模塊加載完成以後,這個回調函數纔會執行,就能夠安全的使用模塊的資源了。其實現就是AMD/RequireJs。AMD雖然是異步,可是會預先加載和執行。
CMD(Common Module Definition),使用seajs,做者是淘寶前端玉伯,兼容幷包解決了RequireJs的問題。
CMD推崇as lazy as possible,儘量的懶加載。
因爲社區的模塊化呼聲很高,ES6開始提供支持模塊的語法,可是瀏覽器目前支持還不夠。
import語句,導入另外一個模塊導出的綁定。
export語句,從模塊中導出函數、對象、值的,供其它模塊import導入用。
創建一個模塊目錄src,而後在這個目錄下新建一個moda.js,內容以下:
export class A{ constructor(x){ this.x = x } show () { console.log(this.x) } } export function foo() { console.log("foo function"); } export const CONSTA = "aaa"
import {A,foo,CONSTA} from "./src/moda.js" foo() a = new A(23) console.log()
VS Code能夠很好的語法支持了,可是運行環境,包括V8引擎,都不能很好的支持模塊化語法。
工具鏈,使用JS工具。
轉譯就是從一種語言代碼轉換到另外一個語言代碼,固然也能夠從高版本轉譯到低版本的支持語句。
因爲JS存在不一樣版本,不一樣瀏覽器兼容的問題,使用transpiler轉譯工具解決
開發中可使用較新的ES6語法,經過轉譯器轉換爲指定的某些版本代碼。
參考文檔 https://babeljs.io/docs/en/6.26.3/index.html
注意當前版本7.x已經有了較大的變化,請參看6.x文檔
能夠測試迭代器的實現,轉換完的內容不須要關心。
function * counter(){ let i = 0; while(true) yield (++i); } g = counter(); console.log(g.next().value);
有以下一些預設presets,咱們先看看有哪些,一下子再進行預設的安裝和配置
presets:
babel-preset-env 當前環境支持的代碼,新target,所有包括es6,es2017,es測試版本等,只寫這一個就能夠了
react轉碼規則
$ npm install --save-dev babel-preset-react
ES2015轉碼規則
$ npm install --save-dev babel-preset-es2015
ES7不一樣階段語法提案的轉碼規則(共有4個階段),選裝一個
$ npm install --save-dev babel-preset-stage-0
$ npm install --save-dev babel-preset-stage-1
$ npm install --save-dev babel-preset-stage-2
$ npm install --save-dev babel-preset-stage-3
在項目目錄中使用
$ npm init
一直回車,會在根目錄下生成一個新文件package.json,內容就是以前回車提示輸入的內容
.npmrc文件
運行環境文件
能夠放到npm的目錄下npmrc文件中,全局影響
能夠放到用戶家目錄中,影響用戶
能夠放到項目根目錄中,影響項目
本次放到項目根目錄中,內容以下
由於國外速度較慢,使用淘寶的
registry=https://registry.npm.taobao.org
$ echo "registry=https://registry.npm.taobao.org" > .npmrc
項目根目錄下執行
$ npm install babel-core babel-cli --save-dev
--save-dev說明
當你爲你的模塊安裝一個依賴模塊時,正常狀況下你得先安裝他們(在模塊根目錄下npm install module-name),而後連同版本號手動將他們添加到模塊配置文件package.json中的依賴裏(dependencies)。開發用。
--save和--save-dev能夠省掉你手動修改package.json文件的步驟。
spm install module-name --save 自動把模塊和版本號添加到dependencies部分
spm install module-name --save-dev 自動把模塊和版本號添加到devdependencies部分
package.json 裏邊的 devDependencies ,後邊的是開發用的依賴
開發依賴前邊去掉dev就是運行依賴,在打包時不要打包開發依賴
安裝完後,在項目根目錄下出現 node_modules目錄 ,裏面有babel相關模塊及依賴的模塊。
替換 scripts 的部分 "test": "echo \"Error: no test specified\" && exit 1" 替換爲 "build": "babel src -d lib"
babel src -d lib 意思是從src目錄中轉譯後的文件輸出到lib目錄
項目根目錄下創建src和lib目錄。
src 是源碼目錄;
lib 是目標目錄。
在目錄根目錄下建立 .babelrc 文件,Json格式。
{ "presets": ["env"] }
env 能夠根據當前環境自動選擇。
安裝依賴
$ npm install babel-preset-env --save-dev
在src中的mod.js
export class A{ constructor(x){ this.x = x } show () { console.log(this.x) } } export function foo() { console.log("foo function"); } export const CONSTA = "aaa"
src目錄下新建index.js
import {A,foo,CONSTA} from "./mod.js" foo() let a = new A(23) a.show() console.log(a,a.x,CONSTA)
直接在VS Code的環境下執行出錯。估計很難有可以正常運行的環境。因此,要轉譯爲ES5的代碼。
在項目根目錄下執行命令
$ npm run build
$ npm run build
> my_test@1.0.0 build D:\project\testjs\my_test > babel src -d lib src\index.js -> lib\index.js src\mod.js -> lib\mod.js
轉譯成功
運行
$ node lib/index.js
使用babel等轉譯器轉譯JS很是流行。
開發者能夠在高版本中使用新的語法特性,提升開發效率,把兼容性問題交給轉譯器處理
說明:導出代碼都在src/mod.js中,導入代碼都寫在src/index.js中。
只容許一個缺省導出,缺省導出能夠是變量、函數、類,但不能使用let、var、const關鍵字做爲默認導出
// 缺省導出 匿名函數 export default function() { console.log('default export function') } // 缺省導入 import defaultFunc from './mod' defaultFunc();
// 缺省導出 命名函數 export default function xyz() { console.log('default export function') } // 缺省導入 import defaultFunc from './mod' defaultFunc();
缺省導入的時候,能夠本身從新命名,能夠不須要和缺省導出時的名稱一致,但最好一致。
缺省導入,不須要在import後使用花括號
export class A{ constructor(x){ this.x = x } show () { console.log(this.x) } } export default function foo() { console.log("foo default function"); } export const CONSTA = "aaa"
import foo, {A,CONSTA}from "./moda" foo() let a = new A(23) a.show() console.log(a,a.x,CONSTA)
導出
/** * 導出舉例 */ // 缺省導出類 export default class { constructor(x) { this.x = x; } show(){ console.log(this.x); } } // 命名導出 函數 export function foo(){ console.log('regular foo()'); } // 函數定義 function bar() { console.log('regular bar()'); } // 變量常量定義 let x = 100; var y = 200; const z = 300; // 導出 export {bar, x, y, z};
導入
/** * ~~~~~~~~~~~~~~~ * 導入舉例 * as 設置別名 */ import defaultCls, {foo, bar, x, y, z as CONST_C} from './moda'; foo(); bar(); console.log(x); // x只讀,不可修改,x++異常 console.log(y); // y只讀 console.log(CONST_C); new defaultCls(1000).show();
也可使用下面的形式,導入全部導出,可是會定義一個新的名詞空間。使用名詞空間能夠避免衝突。
import * as newmod from './mod';
newmod.foo(); newmod.bar(); new newmod.default(2000).show();