chapter1.八、模塊化

模塊化

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開始提供支持模塊的語法,可是瀏覽器目前支持還不夠。

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轉譯工具解決

babel

開發中可使用較新的ES6語法,經過轉譯器轉換爲指定的某些版本代碼。

官網 http://babeljs.io/

參考文檔 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

在項目目錄中使用

$ 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相關模塊及依賴的模塊。

四、修改package.json

替換 scripts 的部分  "test": "echo \"Error: no test specified\" && exit 1" 替換爲 "build": "babel src -d lib"

babel src -d lib 意思是從src目錄中轉譯後的文件輸出到lib目錄

五、準備目錄

項目根目錄下創建src和lib目錄。

src 是源碼目錄;

lib 是目標目錄。

六、配置babel和安裝依賴

在目錄根目錄下建立 .babelrc 文件,Json格式。

{
    "presets": ["env"]
}

env 能夠根據當前環境自動選擇。

安裝依賴

 $ npm install babel-preset-env --save-dev

 七、準備js文件

 在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();
相關文章
相關標籤/搜索