主要知識點:什麼是模塊、模塊中的導出、模塊中的導入
《深刻理解ES6》筆記 目錄webpack
模塊( Modules )是使用不一樣方式加載的 JS 文件(與 JS 原先的腳本加載方式相對)。這種不一樣模式頗有必要,由於它與腳本( script )有大大不一樣的語義:web
可使用 export 關鍵字將已發佈代碼部分公開給其餘模塊。最簡單方法就是將 export放置在任意變量、函數或類聲明以前,從模塊中將它們公開出去:segmentfault
// 導出數據 export var color = "red"; export let name = "Nicholas"; export const magicNumber = 7; // 導出函數 export function sum(num1, num2) { return num1 + num2; } // 導出類 export class Rectangle { constructor(length, width) { this.length = length; this.width = width; } } // 此函數爲模塊私有 function subtract(num1, num2) { return num1 - num2; } // 定義一個函數…… function multiply(num1, num2) { return num1 * num2; } // ……稍後將其導出 export { multiply };
注意:數組
一旦你有了包含導出的模塊,就能在其餘模塊內使用 import 關鍵字來訪問已被導出的功能。 import 語句有兩個部分,一是須要導入的標識符,二是需導入的標識符的來源模塊。
此處是導入語句的基本形式:瀏覽器
import { identifier1, identifier2 } from "./example.js";
/ 單個導入 import { sum } from "./example.js"; console.log(sum(1, 2)); // 3 //不容許對已導入的綁定從新賦值,因而就會致使錯誤 sum = 1; // 出錯
// 多個導入 import { sum, multiply, magicNumber } from "./example.js"; console.log(sum(1, magicNumber)); // 8 console.log(multiply(1, 2)); // 2
還有一種特殊狀況,即容許你將整個模塊看成單一對象進行導入,該模塊的全部導出都會做爲對象的屬性存在。例如:ide
// 徹底導入 import * as example from "./example.js"; console.log(example.sum(1, example.magicNumber)); // 8 console.log(example.multiply(1, 2)); // 2
ES6 的 import 語句爲變量、函數與類建立了只讀綁定,而不像普通變量那樣簡單引用了原始綁定。儘管導入綁定的模塊沒法修改綁定的值,但負責導出的模塊卻能作到這一點。例如,假設你想要使用如下模塊:函數
export var name = "Nicholas"; export function setName(newName) { name = newName; }
當你導入了這兩個綁定後, setName() 函數還能夠改變 name 的值:this
import { name, setName } from "./example.js"; console.log(name); // "Nicholas" setName("Greg"); console.log(name); // "Greg" name = "Nicholas"; // error
function sum(num1, num2) { return num1 + num2; } //將本地名稱sum重命名爲add export { sum as add };
//將導入名稱重命名爲sum import { add as sum } from "./example.js"; console.log(typeof add); // "undefined" console.log(sum(1, 2)); // 3
模塊的默認值( default value ) 是使用 default 關鍵字所指定的單個變量、函數或類,而你在每一個模塊中只能設置一個默認導出,將 default 關鍵字用於多個導出會是語法錯誤。spa
export default function(num1, num2) { return num1 + num2; }
function sum(num1, num2) { return num1 + num2; } export default sum;
function sum(num1, num2) { return num1 + num2; } export { sum as default };
export let color = 'red'; export default function(num1,num2){ return num1+num2; }
import sum from './example.js'; console.log(sum(1,2));
這個導入語句從 example.js 模塊導入了其默認值。注意此處並未使用花括號,與以前在非默認的導入中看到的不一樣。本地名稱 sum 被用於表明目標模塊所默認導出的函數。prototype
import sum, { color } from './example.js'; console.log(sum(1,2)); console.log(color);
逗號將默認的本地名稱與非默認的名稱分隔開,後者仍舊被花括號所包裹。要記住在 import語句中默認名稱必須位於非默認名稱以前。
// 等價於上個例子 import { default as sum, color } from "example"; console.log(sum(1, 2)); // 3 console.log(color); // "red"
若是在當前模塊中對已導入的內容在導出,使用本章已描述過的模式來將已導入的值再導出,就像這樣:
import { sum } from "./example.js"; export { sum }
此方法能奏效,但還可使用單個語句來完成相同任務:
export { sum } from "./example.js";
這種形式的 export 會進入指定模塊查看 sum 的定義,隨後將其導出。固然,你也能夠選擇將一個值用不一樣名稱導出:
export { sum as add } from "./example.js";
若你想未來自另外一個模塊的全部值徹底導出,可使用星號( * )模式:
export * from "./example.js";
有些模塊也許沒有進行任何導出,相反只是修改全局做用域的對象。儘管這種模塊的頂級變量、函數或類最終並不會自動被加入全局做用域,但這並不意味着該模塊沒法訪問全局做用域。諸如 Array 與 Object 之類的內置對象的共享定義在模塊內部是可訪問的,而且對於這些對象的修改會反映到其餘模塊中。
例如,若你想爲全部數組添加一個 pushAll() 方法,你能夠像下面這樣定義一個模塊:
// 沒有導出與導入的模塊 Array.prototype.pushAll = function (items) { // items 必須是一個數組 if (!Array.isArray(items)) { throw new TypeError("Argument must be an array."); } // 使用內置的 push() 與擴展運算符 return this.push(...items); };
這是一個有效的模塊,儘管此處沒有任何導出與導入。
import "./example.js"; let colors = ["red", "green", "blue"]; let items = []; items.pushAll(colors);
有用過webpack打包js模塊的同窗可能有經驗,使用webpack打包了多個js文件,而後放到HTML使用script加載時,若是加載順序不對,就會出現找不到模塊的錯誤。
這是由於模塊之間是有依賴關係的,就像你使用jQuery的時候,必須先加載jQuery的代碼,才能使用jQuery提供的方法。
加載模塊的方法,老是先加載模塊1,再加載模塊2,由於module類型默認使用defer屬性。
<script type="module" src="module1.js"></script> <script type="module" src="module2.js"></script>