前段子產品化基礎
-
概念
前端子產品化其實就是将一個完整的單一的功能整合起來形成單獨的一個功能元件,當需要用的的時候隻需要加載這個元件,然後便可以通過該元件唯一的名稱去使用其中的内容。
- 主流子產品化架構
- commonJS
- AMD
- CMD
- UMD
- ES6規範
commonJS
- commonJS子產品化
- 定義子產品:即一個單獨的檔案就是一個子產品,切該檔案中的作用域獨立,當中的變量是無法被其他檔案引用的,如果要使用需要将其定義為
;global
- 輸出子產品:子產品隻有一個出口,即使用
對象,将需要輸出的内容放入到該對象中;module.exports
- 加載子產品:通過
加載,例如:require
該module的值即對應檔案内部的var module = require('./moduleFile.js');
對象, 然後就可以通過module名稱去引用子產品中的變量和函數了;module.exports
PS:// 定義子產品 module.js var data = "hello commonJS !"; function test1() { alert("hello test1 !"); } function test2() { alert("hello test2 !"); } // 輸出子產品 module.exports = { test1: test1, test2: test2 } // 加載子產品 var module = require('./module.js'); // 使用子產品功能 module.test1(); // "hello test1 !" module.test2(); // "hello test2 !" 總共四個步驟: 定義 -> 輸出 -> 加載 -> 使用
是基于伺服器端開發的,由于commonJS
是同步加載,是以當在浏覽器中是無法運作的,是以就有了下面的異步子產品的出現。require
- 定義子產品:即一個單獨的檔案就是一個子產品,切該檔案中的作用域獨立,當中的變量是無法被其他檔案引用的,如果要使用需要将其定義為
AMD(Asynchronous Module Definition),異步子產品定義
- AMD是一套基于浏覽器端子產品化開發的規範,在進行頁面開發時需要用到該規範的庫函數,即:
requireJS
- requireJS解決了兩個問題
- 多檔案依賴關系處理,被依賴的需要早一步被加載;
- 加載js時候頁面會停止渲染,如果加載的檔案越多,頁面失去響應的時間就會越長;
// 子產品定義 module.js define( ['dependModule', '...', ...], // 這個數組表示該子產品所依賴的子產品名稱 function () { var data = "hello AMD !"; function test1() { alert("hello test1 !); } function test2() { alert("hello test2 !); } return { test1: test1, test2: test2 }; }); // 加載子產品 require(['module'], function (myModule) { // 加載之後的module子產品将會以參數形式:myModule傳入到回調函數中,供使用 // 這裡是子產品加載完成之後的回調函數 myModule.test1(); // "hello test1 !" myModule.test2(); // "hello test2 !" }); // ---------- AMD文法: 子產品定義:使用全局函數`define(id, dependencies, factory);` id: 用來定義子產品辨別,非必選參數,如果沒提供該參數則會預設使用腳本檔案名(不帶擴充名的); dependencies:是表示該子產品所依賴的子產品名稱數組; factory:如果是函數則為該子產品初始化所執行的函數,如果是對象則為該子產品的輸出值。 子產品加載:使用**異步的**`require(dependencies, function (myModule) {});`函數 `dependencies`: 子產品依賴的子產品數組; 回調函數:子產品加載完成後執行的函數,加載的子產品将以參數形式傳入該函數,即:myModule,供使用。
CMD(Common Module Definition)通用子產品定義
- 就近依賴,需要時再進行加載,是以執行順序和書寫順序一緻;這點與AMD不同,AMD是在使用子產品之前将依賴子產品全部加載完成,但由于網絡等其他因素可能導緻依賴子產品下載下傳先後順序不一緻這就導緻了,執行順序可能跟書寫順序不一緻的情況。
// 定義子產品 module.js
define(function (require, exports, module) {
// 在該函數裡面通過require實時的加載依賴子產品
var module1 = require('./module1.js');
module1.test1();
});
// 加載子產品
seajs.use(['module.js'], function (myModule) {
// 除了用的是seajs.use其他和AMD的加載方式類似
});
ES6子產品化,未來标準,但目前未廣泛使用
- 優點
- 類似commonJS,文法更簡潔;
- 類似AMD,直接支援異步加載和配置子產品加載;
- 結構可以做靜态分析,靜态檢測;
- 比commonJS更好的支援循環依賴;
- 文法概述
- 命名式導出方式:每個子產品可以有多個
- 定義式導出方式:每個子產品隻有一個
ES6命名式導出方式
一個子產品通過export聲明來導出多個,需要導出的變量或函數隻需要在聲明最前面加上export關鍵詞即可,然後在需要用的地方使用import導入。這些導出主要根據變量和函數名字來區分,故稱之為命名式導出方式。
例如
```
// module.js
export const PI = 3.1415926;
export function double( r ) {
return 2 * r;
}
export function sum( x, y ) {
return x + y;
}
// 在main.js中使用
import { PI, double, sum } from 'module';
console.log(PI); // 3.1415926
console.log(double(10)); // 20
console.log(sum(10, 8)); // 18
// 使用屬性命名來使用子產品
import { PI, double, sum } as myModule from 'module';
// 這樣就可以通過 myModule.double(10);文法去調用子產品内變量或函數了
console.log( myModule.PI ); // 3.1415926
console.log( myModule.double(10) ); // 20
console.log( myModule.sum(10, 8) ); // 18
```
上面是ES6标準方式,下面是commonJS形式
```
// module.js
var pi = 3.1415926;
function double( r ) {}
function sum( a, b ) {}
module.exports = {
pi: pi,
double: double,
sum: sum
};
// main.js
var module = require('./module.js');
console.log( module.pi );
module.double(10);
module.sum(10, 8);
```
從上述代碼中可知命名式導出方式的使用步驟
1. 在子產品檔案中使用
export
關鍵字将指定的變量或函數導出;
2. 然後在需要使用子產品内函數或變量的地方使用
import
從該子產品檔案中導入這些變量或函數;
ES6定義式導出方式
- 概念:定義式導出了解上就是一個檔案一個子產品,一個子產品一個功能,不像命名式一樣可以一個檔案可以導出多個變量或函數(事實上命名式和定義式可以結合使用,看下面例子)。
-
定義方式:
單函數定義:
類的定義// myFunc.js export default function () { // 這裡面包含了該子產品(或者說該檔案myFunc.js)所有邏輯 // 這種方式該函數不需要名字,因為前面的default關鍵字意思即導出時使用的子產品名字和檔案名一樣即:myFunc }; // main.js import myFunc from 'myFunc'; // 導入後就可以直接使用了 myFunc();
// MyClass.js(首字母大寫) export default class () { // 類内容 // class: 指定該子產品導出的是一個類 }; // main.js var myclass = new MyClass(); // 建立類之後就可以通過執行個體myclass去通路類中的成員和方法了
-
命名式 + 定義式相結合使用
命名式和定義式結合使用:
// module.js export default function () {}; export function test() {}; // main.js import { module, test } from 'module'; // 另外定義式的導出還可以直接用'default'代替,甚至可以定義别名,如下: import module from 'module'; import default from 'module'; import { default as myModule } from 'module'; 三種方式最終結果是一樣的,根據不同需求和習慣選擇。
ES6導入和導出
- ES6提供的幾種導入方式
// 1. 定義式導出和命名式導出,以及相結合的導出 import default from 'module'; // 定義式 import { name1, name2 } from 'module'; // 命名式 import defualt, { name1, name2 } from 'module'; // 結合式 // 2. 導出重命名,即将子產品導出後重命名為指定名字以供使用 import { name1 as rename1, name2 } from 'module';// 即将name1重命名為rename1供使用 // 3. 将整個子產品一起導入,統一用指定屬性名去調用子產品内的内容 import * as moduleName from 'module'; // 4. 值加載不導出子產品 import 'module';
- ES6提供的幾種導出方式
// 1. 在子產品内部使用export導出
export var v1 = ; // 全局變量
export let v2 = ; // 局部變量
export const v3 = ; // 常量
export function f1() {} // 函數
export class MyClass {} // 類
// 2. 子產品内部使用default導出整個表達式
export default ;
export default function (x) { return x; }
export default x => x;
export default class {
constructor(x, y) {
this.x = x;
this.y = y;
}
};
// 3. 将所有想導出的列出來放到檔案最後一起導出
export { v1, v2, v3 };
// 4. 還可以别名導出
export { v1 as vv1, v2 as vv2, v3 };
// 5. 最後一種:重導出,即在一個子產品裡從另一個子產品裡導出内容
// module.js
export { v1, v2 } from 'otherModule';
// 别名
export { v1 as vv1, v2 } from 'otherModule';
ES6子產品中繼資料,通過this module通路目前子產品資料的方式
// main.js
// 通路module中的oData
import { oData } from this module;
console.log( oData );
// 如果想通路目前子產品的oData,就需要
import * as currModule from this module;
console.log( currModule.oData );