首先先搞清楚文件路徑的寫法,這裏我老是記不住,有點暈,正好此次整理一下。javascript
/
爲起始,表示從根目錄開始解析;./
爲起始,表示從當前目錄開始解析;../
爲起始,表示從上級目錄開始解析;CommonJS是nodejs也就是服務器端普遍使用的模塊化機制。
該規範的主要內容是,模塊必須經過module.exports 導出對外的變量或接口,經過 require() 來導入其餘模塊的輸出到當前模塊做用域中。php
根據這個規範,每一個文件就是一個模塊,有本身的做用域,文件中的變量、函數、類等都是對其餘文件不可見的。css
若是想在多個文件分享變量,必須定義爲global對象的屬性。(不推薦)html
在每一個模塊內部,module變量表明當前模塊。它的exports屬性是對外的接口,將模塊的接口暴露出去。其餘文件加載該模塊,實際上就是讀取module.exports變量。java
var x = 5; var addX = function (value) { return value + x; }; module.exports.x = x; module.exports.addX = addX;
require方法用於加載模塊,後綴名默認爲.jsnode
var app = require('./app.js');
模塊加載的順序,按照其在代碼中出現的順序python
根據參數的不一樣格式,require命令去不一樣路徑尋找模塊文件。jquery
通常都會有一個主文件(入口文件),在index.html中加載這個入口文件,而後在這個入口文件中加載其餘文件。es6
能夠經過在package.json中配置main字段來指定入口文件。編程
第一次加載某個模塊時,Node會緩存該模塊。之後再加載該模塊,就直接從緩存取出該模塊的module.exports屬性。
CommonJS模塊的加載機制是,輸入的是被輸出的值的拷貝。也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。
AMD(異步模塊定義)是爲瀏覽器環境設計的,由於 CommonJS 模塊系統是同步加載的,當前瀏覽器環境尚未準備好同步加載模塊的條件。
requirejs即爲遵循AMD規範的模塊化工具。
RequireJS的基本思想是,經過define方法,將代碼定義爲模塊;經過require方法,實現代碼的模塊加載。
define方法用於定義模塊,RequireJS要求每一個模塊放在一個單獨的文件裏。
按照是否依賴其餘模塊,能夠分紅兩種狀況討論。第一種狀況是定義獨立模塊,即所定義的模塊不依賴其餘模塊;第二種狀況是定義非獨立模塊,即所定義的模塊依賴於其餘模塊。
define(function(){ …… return { //返回接口 } })
define定義的模塊能夠返回任何值,不限於對象。
define(['module1','module2'],function(m1,m2){ …… return { //返回接口 } })
要定義的模塊依賴於module1和module2,那麼第一個參數就是依賴的模塊的數組。
第二個參數是一個函數,僅當依賴的模塊都加載成功後纔會被調用。此函數的參數m1,m2與前面數組中的依賴模塊一一對應。
此模塊必須返回一個對象,供其餘模塊調用。
一樣使用require()方法來加載模塊,但因爲是異步的,所以使用回調函數的形式。
require(['foo','bar'],function(foo,bar){ …… })
上面方法表示加載foo和bar兩個模塊,當這兩個模塊都加載成功後,執行一個回調函數。該回調函數就用來完成具體的任務。
require方法也能夠用在define方法內部。
define(function(require){ var otherModule = require('otherModule'); })
require方法容許添加第三個參數,即錯誤處理的回調函數。
require( [ "backbone" ], function ( Backbone ) { return Backbone.View.extend({ /* ... */ }); }, function (err) { // ... } );
require方法自己也是一個對象,它帶有一個config方法,用來配置require.js運行參數。
require.config({ paths: { jquery:'lib/jquery' } });
paths:paths參數指定各個模塊的位置。這個位置能夠是同一個服務器上的相對位置,也能夠是外部網址。能夠爲每一個模塊定義多個位置,若是第一個位置加載失敗,則加載第二個位置。上面就是指定了jquery的位置,那麼就能夠直接在文件中require(['jquery'],function($){})
shim:有些庫不是AMD兼容的,這時就須要指定shim屬性的值。shim能夠理解成「墊片」,用來幫助require.js**加載非AMD規範的庫**。
require.config({ paths: { "backbone": "vendor/backbone", "underscore": "vendor/underscore" }, shim: { "backbone": { deps: [ "underscore" ], exports: "Backbone" }, "underscore": { exports: "_" } } });
在主頁面index.html中先經過script標籤引入require.min.js。
再經過script標籤引入一個入口文件main.js,此入口文件通常用於配置(require.config),以及引入其餘模塊。
因爲Node.js主要用於服務器編程,模塊文件通常都已經存在於本地硬盤,因此加載起來比較快,不用考慮非同步加載的方式,因此CommonJS規範比較適用。可是,若是是瀏覽器環境,要從服務器端加載模塊,這時就必須採用非同步模式,所以瀏覽器端通常採用AMD規範。
AMD規範容許輸出的模塊兼容CommonJS規範,這時define方法須要寫成下面這樣:
define(function(require,exports,module){ var someModule = require("someModule"); var anotherModule = require("anotherModule"); …… exports.asplode = function(){ } })
ES6正式提出了內置的模塊化語法,咱們在瀏覽器端無需額外引入requirejs來進行模塊化。
ES6中的模塊有如下特色:
使用export關鍵字將任意變量、函數或者類公開給其餘模塊。
//導出變量 export var color = "red"; export let name = "cz"; export const age = 25; //導出函數 export function add(num1,num2){ return num1+num2; } //導出類 export class Rectangle { constructor(length, width) { this.length = length; this.width = width; } } function multiply(num1, num2) { return num1 * num2; } //導出對象,即導出引用 export {multiply}
重命名想導出的變量、函數或類的名稱
function sum(num1, num2) { return num1 + num2; } export {sum as add}
這裏將本地的sum函數重命名爲add導出,所以在使用此模塊的時候必須使用add這個名稱。
模塊的默認值是使用 default 關鍵字所指定的單個變量、函數或類,而你在每一個模塊中只能設置一個默認導出。
export default function(num1, num2) { return num1 + num2; }
此模塊將一個函數做爲默認值進行了導出, default 關鍵字標明瞭這是一個默認導出。此函數並不須要有名稱,由於它就表明這個模塊自身。對比最前面使用export導出的函數,並非匿名函數而是必須有一個名稱用於加載模塊的時候使用,可是默認導出則無需一個名字,由於模塊名就表明了這個導出值。
也可使用重命名語法來導出默認值。
function sum(num1, num2) { return num1 + num2; } export { sum as default };
在模塊中使用import關鍵字來導入其餘模塊。
import 語句有兩個部分,一是須要導入的標識符,二是需導入的標識符的來源模塊。此處是導入語句的基本形式:
import { identifier1,identifier2 } from "./example.js"
當從模塊導入了一個綁定時,你不能在當前文件中再定義另外一個同名變量(包括導入另外一個同名綁定),也不能在對應的 import 語句以前使用此標識符,更不能修改它的值。
若是一個模塊只導出了一個函數(或變量或類),或者導出了多個接口可是隻選擇導入其中的一個,那麼就能夠寫成下面單個導入的模式:
import {sum} from './example.js'
從一個模塊中導入多個綁定:
import {sum,multiply} from './example.js'
還有一種狀況,就是將整個模塊當作單一對象導入,該模塊的全部導出都會做爲對象的屬性存在:
import * as example from './example.js' example.sum(1,2); example.multiply(2,3);
在此代碼中, example.js 中全部導出的綁定都被加載到一個名爲 example 的對象中,具名導出( sum() 函數、 multiple() 函數)都成爲 example 的可用屬性。
這種導入格式被稱爲命名空間導入,這是由於該 example 對象並不存在於 example.js 文件中,而是做爲一個命名空間對象被建立使用,其中包含了 example.js 的全部導出成員。
然而要記住,不管你對同一個模塊使用了多少次 import 語句,該模塊都只會被執行一次。
在導出模塊的代碼執行以後,已被實例化的模塊就被保留在內存中,並隨時都能被其餘 import 所引用.
import { sum } from "./example.js"; import { multiply } from "./example.js"; import { magicNumber } from "./example.js";
儘管此處的模塊使用了三個 import 語句,但 example.js 只會被執行一次。若同一個應用中的其餘模塊打算從 example.js 導入綁定,則那些模塊都會使用這段代碼中所用的同一個模塊實例。
與導出相同,咱們一樣能夠重命名導入的綁定:
import { sum as add} from './example.js'
若是一個模塊導出了默認值,那麼能夠這樣導入默認值:
import sum from "./example.js";
這個導入語句從 example.js 模塊導入了其默認值。注意此處並未使用花括號,與以前在非默認的導入中看到的不一樣。本地名稱 sum 被用於表明目標模塊所默認導出的函數,所以無需使用花括號。
若是一個模塊既導出了默認值、又導出了一個或更多非默認的綁定的模塊:
export let color = "red"; export default function(num1, num2) { return num1 + num2; }
能夠像下面這樣使用一條import語句來導入它的全部導出綁定:
import sum,{color} from "./example.js"
逗號將默認的本地名稱與非默認的名稱分隔開,後者仍舊被花括號所包裹。
要記住在 import 語句中默認名稱必須位於非默認名稱以前。
有時想在當前的模塊中將已導入的內容再導出去,能夠像下面這樣寫:
import {sum} from './example.js' …… export {sum}
可是有一種更簡潔的方法:
export {sum} from './example.js'
一樣能夠重命名:
export { sum as add } from "./example.js";
也可使用徹底導出:
export * from "./example.js";
export 與 import 都有一個重要的限制,那就是它們必須被用在其餘語句或表達式的外部,而不能使用在if等代碼塊內部。緣由之一是模塊語法須要讓 JS 能靜態判斷須要導出什麼,正由於此,你只能在模塊的頂級做用域使用 export與import。