1. 程式人生 > >ES6新特性之模組Module用法解析

ES6新特性之模組Module用法解析

這篇文章主要介紹了ES6新特性之模組Module用法,簡要說明了模組Module的概念、功能並結合例項形式分析了模組Module的使用方法與相關注意事項,需要的朋友可以參考下

##一、Module簡介 ES6的Class只是面向物件程式設計的語法糖,升級了ES5的建構函式的原型鏈繼承的寫法,並沒有解決模組化問題。Module功能就是為了解決這個問題而提出的。

歷史上,JavaScript一直沒有模組(module)體系,無法將一個大程式拆分成互相依賴的小檔案,再用簡單的方法拼裝起來。其他語言都有這項功能。

在ES6之前,社群制定了一些模組載入方案,最主要的有CommonJS和AMD兩種。前者用於伺服器,後者用於瀏覽器。ES6在語言規格的層面上,實現了模組功能,而且實現得相當簡單,完全可以取代現有的CommonJS和AMD規範,成為瀏覽器和伺服器通用的模組解決方案。

ES6模組的設計思想,是儘量的靜態化,使得編譯時就能確定模組的依賴關係(這種載入稱為“編譯時載入”),以及輸入和輸出的變數。CommonJS和AMD模組,都只能在執行時確定這些東西。 瀏覽器使用ES6模組的語法如下。

<script type="module" src="fs.js"></script>

上面程式碼在網頁中插入一個模組fs.js,由於type屬性設為module,所以瀏覽器知道這是一個ES6模組。

// ES6載入模組
import { stat, exists, readFile } from 'fs';

上面程式碼通過import去載入一個Module,載入其中的一些方法。

##二、import 和 export

模組功能主要由兩個命令構成:export和import。export命令用於規定模組的對外介面,import命令用於輸入其他模組提供的功能。 一個模組就是一個獨立的檔案。該檔案內部的所有變數,外部無法獲取。如果你希望外部能夠讀取模組內部的某個變數,就必須使用export關鍵字輸出該變數。下面是一個JS檔案,裡面使用export命令輸出變數。

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

export的寫法,除了像上面這樣,還有另外一種。(推薦這種,因為這樣就可以在指令碼尾部,一眼看清楚輸出了哪些變數。)

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};

export命令除了輸出變數,還可以輸出函式或類(class)。通常情況下,export輸出的變數就是本來的名字,但是可以使用as關鍵字重新命名。

function v1() { ... }
function v2() { ... }
export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

使用export命令定義了模組的對外介面以後,其他JS檔案就可以通過import命令載入這個模組(檔案)。

// main.js
import {firstName, lastName, year} from './profile';
function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

上面程式碼的import命令,就用於載入profile.js檔案,並從中輸入變數。import命令接受一個物件(用大括號表示),裡面指定要從其他模組匯入的變數名。大括號裡面的變數名,必須與被匯入模組(profile.js)對外介面的名稱相同。 如果想為輸入的變數重新取一個名字,import命令要使用as關鍵字,將輸入的變數重新命名。

import { lastName as surname } from './profile';

import命令具有提升效果,會提升到整個模組的頭部,首先執行。

foo();
import { foo } from 'my_module';
//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

##三、模組的整體載入

除了指定載入某個輸出值,還可以使用整體載入,即用星號(*)指定一個物件,所有輸出值都載入在這個物件上面。 有一個circle.js檔案,它輸出兩個方法area和circumference。 現在,載入這個模組。

// main.js
import { area, circumference } from './circle';
console.log('圓面積:' + area(4));
console.log('圓周長:' + circumference(14));

上面寫法是逐一指定要載入的方法,整體載入的寫法如下。

import * as circle from './circle';
console.log('圓面積:' + circle.area(4));
console.log('圓周長:' + circle.circumference(14));

##四、export default

為了給使用者提供方便,讓他們不用閱讀文件就能載入模組,就要用到export default命令,為模組指定預設輸出。

// export-default.js
export default function () {
  console.log('foo');
}

上面程式碼是一個模組檔案export-default.js,它的預設輸出是一個函式。 其他模組載入該模組時,import命令可以為該匿名函式指定任意名字。

// import-default.js
import customName from './export-default';
customName(); // 'foo'

需要注意的是,這時import命令後面,不使用大括號。 本質上,export default就是輸出一個叫做default的變數或方法,然後系統允許你為它取任意名字。它後面不能跟變數宣告語句。

// 正確
var a = 1;
export default a;
// 錯誤
export default var a = 1;

##五、ES6模組載入的實質

ES6模組載入的機制,與CommonJS模組完全不同。CommonJS模組輸出的是一個值的拷貝,而ES6模組輸出的是值的引用。 CommonJS模組輸出的是被輸出值的拷貝,也就是說,一旦輸出一個值,模組內部的變化就影響不到這個值。請看下面這個模組檔案lib.js的例子。

// lib.js
var counter = 3;
function incCounter() {
 counter++;
}//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860
module.exports = {
 counter: counter,
 incCounter: incCounter,
};

上面程式碼輸出內部變數counter和改寫這個變數的內部方法incCounter。然後,在main.js裡面載入這個模組。

// main.js
var mod = require('./lib');
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3

上面程式碼說明,lib.js模組載入以後,它的內部變化就影響不到輸出的mod.counter了。這是因為mod.counter是一個原始型別的值,會被快取。除非寫成一個函式,才能得到內部變動後的值。

// lib.js
var counter = 3;
function incCounter() {
 counter++;
}//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860
module.exports = {
 get counter() {
  return counter
 },
 incCounter: incCounter,
};

上面程式碼中,輸出的counter屬性實際上是一個取值器函式。現在再執行main.js,就可以正確讀取內部變數counter的變動了。 ES6模組的執行機制與CommonJS不一樣,它遇到模組載入命令import時,不會去執行模組,而是隻生成一個動態的只讀引用。等到真的需要用到時,再到模組裡面去取值,換句話說,ES6的輸入有點像Unix系統的“符號連線”,原始值變了,import輸入的值也會跟著變。因此,ES6模組是動態引用,並且不會快取值,模組裡面的變數繫結其所在的模組。 還是舉上面的例子。

// lib.js
export let counter = 3;
export function incCounter() {
 counter++;
}//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4

上面程式碼說明,ES6模組輸入的變數counter是活的,完全反應其所在模組lib.js內部的變化。 由於ES6輸入的模組變數,只是一個“符號連線”,所以這個變數是隻讀的,對它進行重新賦值會報錯。

// lib.js
export let obj = {};
// main.js
import { obj } from './lib';
obj.prop = 123; // OK
obj = {}; // TypeError

上面程式碼中,main.js從lib.js輸入變數obj,可以對obj新增屬性,但是重新賦值就會報錯。因為變數obj指向的地址是隻讀的,不能重新賦值,這就好比main.js創造了一個名為obj的const變數。 最後,export通過介面,輸出的是同一個值。不同的指令碼載入這個介面,得到的都是同樣的例項。

// mod.js
function C() {
 this.sum = 0;
 this.add = function () {
  this.sum += 1;
 };
 this.show = function () {
  console.log(this.sum);
 };//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860=
}//幫助突破技術瓶頸,提升思維能力
export let c = new C();

上面的指令碼mod.js,輸出的是一個C的例項。不同的指令碼載入這個模組,得到的都是同一個例項。

// x.js
import {c} from './mod';
c.add();
// y.js
import {c} from './mod';
c.show();
// main.js
import './x';
import './y';

現在執行main.js,輸出的是1。這就證明了x.js和y.js載入的都是C的同一個例項。

結語

感謝您的觀看,如有不足之處,歡迎批評指正。

本次給大家推薦一個免費的學習群,裡面概括移動應用網站開發,css,html,webpack,vue node angular以及面試資源等。 對web開發技術感興趣的同學,歡迎加入Q群:864305860,不管你是小白還是大牛我都歡迎,還有大牛整理的一套高效率學習路線和教程與您免費分享,同時每天更新視訊資料。 最後,祝大家早日學有所成,拿到滿意offer,快速升職加薪,走上人生巔峰。

這篇文章主要介紹了ES6新特性之模組Module用法,簡要說明了模組Module的概念、功能並結合例項形式分析了模組Module的使用方法與相關注意事項,需要的朋友可以參考下

##一、Module簡介 ES6的Class只是面向物件程式設計的語法糖,升級了ES5的建構函式的原型鏈繼承的寫法,並沒有解決模組化問題。Module功能就是為了解決這個問題而提出的。

歷史上,JavaScript一直沒有模組(module)體系,無法將一個大程式拆分成互相依賴的小檔案,再用簡單的方法拼裝起來。其他語言都有這項功能。

在ES6之前,社群制定了一些模組載入方案,最主要的有CommonJS和AMD兩種。前者用於伺服器,後者用於瀏覽器。ES6在語言規格的層面上,實現了模組功能,而且實現得相當簡單,完全可以取代現有的CommonJS和AMD規範,成為瀏覽器和伺服器通用的模組解決方案。

ES6模組的設計思想,是儘量的靜態化,使得編譯時就能確定模組的依賴關係(這種載入稱為“編譯時載入”),以及輸入和輸出的變數。CommonJS和AMD模組,都只能在執行時確定這些東西。 瀏覽器使用ES6模組的語法如下。

<script type="module" src="fs.js"></script>

上面程式碼在網頁中插入一個模組fs.js,由於type屬性設為module,所以瀏覽器知道這是一個ES6模組。

// ES6載入模組
import { stat, exists, readFile } from 'fs';

上面程式碼通過import去載入一個Module,載入其中的一些方法。

##二、import 和 export

模組功能主要由兩個命令構成:export和import。export命令用於規定模組的對外介面,import命令用於輸入其他模組提供的功能。 一個模組就是一個獨立的檔案。該檔案內部的所有變數,外部無法獲取。如果你希望外部能夠讀取模組內部的某個變數,就必須使用export關鍵字輸出該變數。下面是一個JS檔案,裡面使用export命令輸出變數。

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

export的寫法,除了像上面這樣,還有另外一種。(推薦這種,因為這樣就可以在指令碼尾部,一眼看清楚輸出了哪些變數。)

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};

export命令除了輸出變數,還可以輸出函式或類(class)。通常情況下,export輸出的變數就是本來的名字,但是可以使用as關鍵字重新命名。

function v1() { ... }
function v2() { ... }
export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

使用export命令定義了模組的對外介面以後,其他JS檔案就可以通過import命令載入這個模組(檔案)。

// main.js
import {firstName, lastName, year} from './profile';
function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

上面程式碼的import命令,就用於載入profile.js檔案,並從中輸入變數。import命令接受一個物件(用大括號表示),裡面指定要從其他模組匯入的變數名。大括號裡面的變數名,必須與被匯入模組(profile.js)對外介面的名稱相同。 如果想為輸入的變數重新取一個名字,import命令要使用as關鍵字,將輸入的變數重新命名。

import { lastName as surname } from './profile';

import命令具有提升效果,會提升到整個模組的頭部,首先執行。

foo();
import { foo } from 'my_module';
//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

##三、模組的整體載入

除了指定載入某個輸出值,還可以使用整體載入,即用星號(*)指定一個物件,所有輸出值都載入在這個物件上面。 有一個circle.js檔案,它輸出兩個方法area和circumference。 現在,載入這個模組。

// main.js
import { area, circumference } from './circle';
console.log('圓面積:' + area(4));
console.log('圓周長:' + circumference(14));

上面寫法是逐一指定要載入的方法,整體載入的寫法如下。

import * as circle from './circle';
console.log('圓面積:' + circle.area(4));
console.log('圓周長:' + circle.circumference(14));

##四、export default

為了給使用者提供方便,讓他們不用閱讀文件就能載入模組,就要用到export default命令,為模組指定預設輸出。

// export-default.js
export default function () {
  console.log('foo');
}

上面程式碼是一個模組檔案export-default.js,它的預設輸出是一個函式。 其他模組載入該模組時,import命令可以為該匿名函式指定任意名字。

// import-default.js
import customName from './export-default';
customName(); // 'foo'

需要注意的是,這時import命令後面,不使用大括號。 本質上,export default就是輸出一個叫做default的變數或方法,然後系統允許你為它取任意名字。它後面不能跟變數宣告語句。

// 正確
var a = 1;
export default a;
// 錯誤
export default var a = 1;

##五、ES6模組載入的實質

ES6模組載入的機制,與CommonJS模組完全不同。CommonJS模組輸出的是一個值的拷貝,而ES6模組輸出的是值的引用。 CommonJS模組輸出的是被輸出值的拷貝,也就是說,一旦輸出一個值,模組內部的變化就影響不到這個值。請看下面這個模組檔案lib.js的例子。

// lib.js
var counter = 3;
function incCounter() {
 counter++;
}//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860
module.exports = {
 counter: counter,
 incCounter: incCounter,
};

上面程式碼輸出內部變數counter和改寫這個變數的內部方法incCounter。然後,在main.js裡面載入這個模組。

// main.js
var mod = require('./lib');
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3

上面程式碼說明,lib.js模組載入以後,它的內部變化就影響不到輸出的mod.counter了。這是因為mod.counter是一個原始型別的值,會被快取。除非寫成一個函式,才能得到內部變動後的值。

// lib.js
var counter = 3;
function incCounter() {
 counter++;
}//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860
module.exports = {
 get counter() {
  return counter
 },
 incCounter: incCounter,
};

上面程式碼中,輸出的counter屬性實際上是一個取值器函式。現在再執行main.js,就可以正確讀取內部變數counter的變動了。 ES6模組的執行機制與CommonJS不一樣,它遇到模組載入命令import時,不會去執行模組,而是隻生成一個動態的只讀引用。等到真的需要用到時,再到模組裡面去取值,換句話說,ES6的輸入有點像Unix系統的“符號連線”,原始值變了,import輸入的值也會跟著變。因此,ES6模組是動態引用,並且不會快取值,模組裡面的變數繫結其所在的模組。 還是舉上面的例子。

// lib.js
export let counter = 3;
export function incCounter() {
 counter++;
}//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4

上面程式碼說明,ES6模組輸入的變數counter是活的,完全反應其所在模組lib.js內部的變化。 由於ES6輸入的模組變數,只是一個“符號連線”,所以這個變數是隻讀的,對它進行重新賦值會報錯。

// lib.js
export let obj = {};
// main.js
import { obj } from './lib';
obj.prop = 123; // OK
obj = {}; // TypeError

上面程式碼中,main.js從lib.js輸入變數obj,可以對obj新增屬性,但是重新賦值就會報錯。因為變數obj指向的地址是隻讀的,不能重新賦值,這就好比main.js創造了一個名為obj的const變數。 最後,export通過介面,輸出的是同一個值。不同的指令碼載入這個介面,得到的都是同樣的例項。

// mod.js
function C() {
 this.sum = 0;
 this.add = function () {
  this.sum += 1;
 };
 this.show = function () {
  console.log(this.sum);
 };//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860=
}//幫助突破技術瓶頸,提升思維能力
export let c = new C();

上面的指令碼mod.js,輸出的是一個C的例項。不同的指令碼載入這個模組,得到的都是同一個例項。

// x.js
import {c} from './mod';
c.add();
// y.js
import {c} from './mod';
c.show();
// main.js
import './x';
import './y';

現在執行main.js,輸出的是1。這就證明了x.js和y.js載入的都是C的同一個例項。

結語

感謝您的觀看,如有不足之處,歡迎批評指正。