深刻理解ES6筆記(十三)用模塊封裝代碼

主要知識點:什麼是模塊、模塊中的導出、模塊中的導入
圖片描述

《深刻理解ES6》筆記 目錄webpack

模塊的定義

模塊( Modules )是使用不一樣方式加載的 JS 文件(與 JS 原先的腳本加載方式相對)。這種不一樣模式頗有必要,由於它與腳本( script )有大大不一樣的語義:web

  1. 模塊代碼自動運行在嚴格模式下,而且沒有任何辦法跳出嚴格模式;
  2. 在模塊的頂級做用域建立的變量,不會被自動添加到共享的全局做用域,它們只會在模塊頂級做用域的內部存在;
  3. 模塊頂級做用域的 this 值爲 undefined ;
  4. 模塊不容許在代碼中使用 HTML 風格的註釋(這是 JS 來自於早期瀏覽器的歷史遺留特性);
  5. 對於須要讓模塊外部代碼訪問的內容,模塊必須導出它們;
  6. 容許模塊從其餘模塊導入綁定。

模塊的導出

可使用 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
};

注意:數組

  • 除了 export 關鍵字以外,每一個聲明都與正常形式徹底同樣。
  • 每一個被導出的函數或類都有名稱,這是由於導出的函數聲明與類聲明必需要有名稱。你不能使用這種語法來導出匿名函數或匿名類,除非使用了 default 關鍵字

模塊的導入

一旦你有了包含導出的模塊,就能在其餘模塊內使用 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>
相關文章
相關標籤/搜索