es6 Module

前言: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 模塊格式。目前,經過各類工具庫,其實已經作到了這一點。
  • 未來瀏覽器的新 API 就能用模塊格式提供,再也不必須作成全局變量或者navigator對象的屬性。
  • 再也不須要對象做爲命名空間(好比Math對象),將來這些功能能夠經過模塊提供。

關於es6模塊的特性設計

1、嚴格模式:

  es6模塊默認使用嚴格模式,無論你有沒有使用  'use strict' 

2、export

  模塊功能主要由兩個命令構成:exportimportexport命令用於規定模塊的對外接口,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
相關文章
相關標籤/搜索