在模塊化被寫入 ECMAScript 標準以前, 已經存在各類模塊化的實現方式和對應的語法, 例如 AMD, CMD, commonJS 等. 本文只討論 ES6 標準下的模塊化語法.模塊化
當咱們但願全局做用域更加乾淨,而不是處處都有命名衝突之類的問題;函數
當咱們但願一段代碼擁有本身的做用域, 並且不要被其餘代碼所污染;ui
當咱們但願本身的程序更加井井有理;this
當......spa
這也是 ES6 但願解決的問題, 因此將模塊化定爲了標準.code
模塊是一段JavaScript代碼, 這段代碼會自動運行、並且是在嚴格模式下、而且沒法退出運行。對象
this
是 undefined
, 並非 window
或 global
模塊和腳本初看起來很類似, 他們均可以存在一個單獨的文件中, 均可以被其餘模塊(腳本)引入, 也能夠引入其餘模塊(腳本)的數據, 彷佛很難說出他們之間的區別.ip
可是其實他們的區別很是明顯, 用一句話就能夠歸納: 咱們能夠按需導入模塊中的數據, 可是不能按需導入腳本中的數據。作用域
對於腳本,咱們一旦導入了它, 就會將腳本中的全部數據全都導入到了全局做用域中, 這樣看起來仍是挺亂的。string
而對於模塊, 則能夠只導入咱們須要的數據。雖然一個模塊可能會暴露出不少的變量、函數和對象, 但咱們能夠只把須要的那一部分導入進來使用。
export
和 import
export
將模塊中的數據暴露給其餘模塊使用的語法有兩種, 分別以下:
// 定義一個變量
let name = 'doug';
// 暴露這個變量
export name;
// 定義一個函數
function say(){
console.log('hello ' + name);
}
// 暴露這個函數
export say;
// 定義一個類
class Student {
constructor(name, age){
this.name = name;
this.age = age;
}
}
// 暴露這個類
export Student;
// 定義一個函數,並且不把它暴露出去
function privateFunc(){
console.log('我是私有成員,沒有被暴露出去,因此別人沒有辦法訪問到我');
}
複製代碼
上面的操做能夠分爲兩個過程, 先定義、再暴露。其實能夠簡化爲一句代碼: 2. 在定義變量的同時暴露數據, 只要在聲明符以前加上 export 就能夠.
// 定義一個變量並暴露
export let name = 'doug';
// 定義一個函數並暴露
export function say(){
console.log('hello ' + name);
}
// 定義一個類並暴露
export class Student {
constructor(name, age){
this.name = name;
this.age = age;
}
}
// 定義一個函數,並不把它暴露出去, 其餘模塊從外部沒法訪問這個函數
function privateFunc(){
console.log('我是私有成員,沒有被暴露出去,因此別人沒有辦法訪問到我');
}
複製代碼
注意, 不暴露出去的數據是從外部訪問不到的, 例如上面例子中的
privateFunc
函數.
import
從別的模塊獲得數據以供本身使用, 要用 import 關鍵字。在導入以前, 要先明確兩個問題: 一是從哪一個模塊導入? 二是想導入模塊中的什麼數據?
在明確從哪導入和導入什麼以後,就能夠按照下面的語法來寫了:
import { 數據1, 數據2, ... , 數據n } from 模塊名
複製代碼
例如,從 a 模塊中導入 name 變量 和 say 函數:
import { name, say } from './a.js';
複製代碼
這樣就把 name 和 say 從 a 模塊導入進本模塊中了,如今就可使用它們了, 例如輸出 name 的值, 或者調用 say 這個函數:
console.log(name);
say();
複製代碼
導入的數據是沒有辦法直接改變的。好比,咱們沒法直接給 name 從新賦值, 這樣會報錯。
import { name } from './a.js';
name = 'new name'; // Error 錯誤
複製代碼
可是能夠間接的修改這個變量的值. 假如在模塊 a 中定義了一個能夠修改 name 值的函數, 則能夠經過調用這個函數來修改 name 的值了. a 模塊中的內容:
... 包括 name 在內的其餘數據
function updateName(newName){
name = newName;
}
複製代碼
導入 a模塊的 updateName
函數來修改 name 的值:
import { name, updateName } from './a.js';
updateName('new Name'); // name的值已經被修改成了 "new name"
複製代碼
當想用一行代碼導入一個模塊暴露出來的全部數據時, 用上面的方法可能比較困難, 由於一個模塊暴露出來的方法可能不少, 把每一個變量名都寫出來的方法就不夠靈活了.
這個時候能夠用命名空間導入的方法, 即將一個模塊暴露出來的全部的數據掛載到一個對象上,經過這個對象來調用這些數據, 例如:
import * as aObj from './a.js'; // a 模塊全部暴露出的數據都掛到了 aObj 上
// 經過 aObj 來訪問和調用 a 模塊中的變量和方法
console.log(aObj.name);
aObj.say();
複製代碼
as
對導入和要暴露出去的數據重命名若是想將數據以別的名稱暴露出去, 可使用 as
關鍵字, 語法爲: export { 原名稱 as 新名稱 }
.
這樣在其餘模塊中就能夠用這個新的名稱來導入這個數據了, 例如將函數 say 以 speak 爲名稱暴露出去:
export {say as speak};
複製代碼
那麼其餘模塊就要用 speak 來導入這個函數了: import { speak } from './a.js'
在導入一個數據時, 也能夠對它重命名, 並使用重命名以後的名稱來訪問它, 例如將它命名爲 Howling, 以後就可使用 howling 來訪問這個函數了:
import { speak as howling} from './a.js'; // 導入時重命名
howling(); // 用新名字調用這個函數
複製代碼
default
每一個模塊能夠將一個變量、函數或者類做爲默認值暴露出去.
將一個值做爲默認值暴露出去的語法有3種,分別是:
// 1. 定義的時候就暴露
export default function(){
console.log('方法1暴露函數爲默認值');
}
// 2. 先定義後暴露
let name = 'doug';
export default name;
// 3. 將這個值用 as 命名爲 default 暴露
class Student{ // ... }
export {Student as default};
複製代碼
導入默認值的語法和導入非默認值的語法略有不一樣. 導入一個模塊暴露出的默認值, 並不用 {}
來包裹, 並且不用使用 as
關鍵字就能夠將這個默認值重命名: 例如導入上面例子中的 name, 並將其重命名爲 familyName
import familyName from './a.js';
複製代碼
在一行語句中同時導入默認值和非默認值的語法很是簡單, 就是將這兩種導入的方式結合起來, 非默認值用{}
括起來, 而默認值不用. 語法爲:
import 默認值 { 非默認值 } from './a.js';
複製代碼
有時候須要將從其餘模塊導入的某些數據再暴露出去, 這有兩種語法
import { name } from './a.js'; // 導入
export {name}; // 暴露
複製代碼
export { name } from './a.js';
複製代碼
也能夠重命名後再暴露出去
export { name as lastName } from './a.js';
複製代碼
#完. 文章或有疏漏之處, 歡迎指正.