前言:es6
這是阮一峯老師的ECMA6入門module一章的縮減,只抽取了我在項目中有用到的內容。帶着問題去看老師的教程。感受吸取更快,也明白了偶爾遇到的export不出來的問題。瀏覽器
es6模塊設計思想:服務器
ES6 模塊的設計思想,是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時肯定這些東西。好比,CommonJS 模塊就是對象,輸入時必須查找對象屬性。app
es6模塊不是對象:函數
// CommonJS模塊 let { stat, exists, readFile } = require('fs'); // 等同於 let _fs = require('fs'); let stat = _fs.stat, exists = _fs.exists, readfile = _fs.readfile;
上面代碼的實質是總體加載fs
模塊(即加載fs
的全部方法),生成一個對象(_fs
),而後再從這個對象上面讀取3個方法。這種加載稱爲「運行時加載」,由於只有運行時才能獲得這個對象,致使徹底沒辦法在編譯時作「靜態優化」。工具
ES6 模塊不是對象,而是經過export
命令顯式指定輸出的代碼,再經過import
命令輸入。不會加載整個fs。優化
// ES6模塊 import { stat, exists, readFile } from 'fs';
因爲 ES6 模塊是編譯時加載,使得靜態分析成爲可能。ui
除了靜態加載帶來的各類好處,ES6 模塊還有如下好處。spa
UMD
模塊格式了,未來服務器和瀏覽器都會支持 ES6 模塊格式。目前,經過各類工具庫,其實已經作到了這一點。navigator
對象的屬性。Math
對象),將來這些功能能夠經過模塊提供。關於es6模塊的特性設計
1、嚴格模式:
es6模塊默認使用嚴格模式,無論你有沒有使用 'use strict'
2、export
模塊功能主要由兩個命令構成:export
和import
。export
命令用於規定模塊的對外接口,import
命令用於輸入其餘模塊提供的功能。
須要特別注意的是,export
命令規定的是對外的接口,必須與模塊內部的變量創建一 一對應關係。
這裏的意思是不能直接輸入一個變量,函數,類
// 報錯 export 1; // 報錯 var m = 1; export m;
正確的,有一一對應關係的export,函數 function,類 class 也是要遵照這種規則的。
// 寫法一:這種我不理解 export var m = 1; // 寫法二:輸出一個對象,這個對象有一個 m 屬性,m屬性與m變量,一一對應 var m = 1; export {m}; // 寫法三:輸出一個n,n與m一一對應 var n = 1; export {n as m};
// 報錯:輸出的 f 就是 函數 f 沒有對應關係 function f() {} export f; // 正確 export function f() {}; // 正確 function f() {} export {f};
export的換名輸出
function v1() { ... } function v2() { ... } export { v1 as streamV1, v2 as streamV2, v2 as streamLatestVersion };
3、import
使用export
命令定義了模塊的對外接口之後,其餘 JS 文件就能夠經過import
命令加載這個模塊。
注意:import在編譯階段執行,能夠理解爲跟變量提高,函數提高有同樣的特性,可是比這兩種提高晚一點執行。
foo(); import { foo } from 'my_module';
上面的代碼不會報錯,由於import
的執行早於foo
的調用。這種行爲的本質是,import
命令是編譯階段執行的,在代碼運行以前。
import
語句會執行所加載的模塊,所以能夠有下面的寫法。只執行一下lodash,可是不輸入任何值
import 'lodash';
只想列出不一樣的import寫法:
// 變量名與export一一對應 import {firstName, lastName, year} from './profile'; // 使用新變量名代替 import { lastName as surname } from './profile';
4、模塊的總體加載
一個模塊中能夠有多個export,import中可使用 * 把他們所有收在一個對象中 * as mymodule
import * as circle from './circle';
5、export default 命令
爲模塊設置默認輸出,在import的時候不須要使用{},也能夠隨便給一個名字這個默認輸出。
// export-default.js export default function foo() { console.log('foo'); } // 或者寫成 function foo() { console.log('foo'); } export default foo; // import import xxx from 'export-default.js'
本質上,export default
就是輸出一個叫作default
的變量或方法,而後系統容許你爲它取任意名字。
// modules.js function add(x, y) { return x * y; } export {add as default}; // 等同於 // export default add; // app.js import { default as xxx } from 'modules'; // 等同於 // import xxx from 'modules';
正是由於export
default
命令其實只是輸出一個叫作default
的變量,因此它後面不能跟變量聲明語句。(怪不得總是說,找不到模塊)
// 正確 export var a = 1; // 正確 var a = 1; export default a; // 錯誤 export default var a = 1;
同時想要兩種輸出
import _, { each } from 'lodash';
8、es6模塊加載的實質
ES6模塊加載的機制,與CommonJS模塊徹底不一樣。CommonJS模塊輸出的是一個值的拷貝(值類型是拷貝,引用類型是引用),而ES6模塊輸出的是值的引用(值類型,引用類型都是引用)。
問題1:
commonJS 獲得的是一個複製,require後獲得的mod.counter,跟lib.js裏面的counter已經沒有聯繫,(能夠理解爲require多少次,複製多少份)
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, }; // main.js var mod = require('./lib'); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // 3
es6模塊的優勢就是共享一份,由於它輸出的僅僅是引用
// lib.js export let counter = 3; export function incCounter() { counter++; } // main.js import { counter, incCounter } from './lib'; console.log(counter); // 3 incCounter(); console.log(counter); // 4