export,,export default,import || export,module.exports,require

參考地址 http://www.reibang.com/p/be2d4eab3878

module.exports

Node應用由模塊組成,采用CommonJS模塊規(guī)范。根據(jù)這個規(guī)范获洲,每個文件就是一個模塊磨取,有自己的作用域元潘。在這些文件里面定義的變量畔乙、函數(shù)、類翩概,都是私有的啸澡,對外不可見,因此規(guī)避掉了作用域污染氮帐。

根據(jù)CommonJS規(guī)定,每個模塊內(nèi)部洛姑,module變量代表當前模塊上沐,這個變量是一個對象,它的exports屬性(即module.exports)是對外的接口楞艾。加載某個模塊参咙,其實就是加載該模塊的exports屬性。

舉例:通過module.exports輸出變量 age 和 sayHelloTo 函數(shù)硫眯。

//./MyModule.js
    var age = 7; 
    var sayHelloTo= function (name) { 
        return "hello " + name;
    }; 
    module.exports.age = age; 
    module.exports.sayHelloTo=sayHelloTo;

require:用于加載模塊

var temp = require('./MyModule.js');  
//這里也可以使用 import temp from './MyModule.js'
console.log(temp.age); // 7 
console.log(temp.sayHelloTo("Steve")); // hello 

exports 與 module.exports

為了方便蕴侧,node為每個模塊提供了一個exports變量,指向module.exports两入。這等同于在每個模塊頭部净宵,有這么一行代碼:

var exports = module.exports;

因此,我們可以直接在exports對象上添加方法(等同于在 module.exports 添加一樣)

//./MyModule.js
    var age = 7; 
    var sayHelloTo= function (name) { 
        return "hello " + name;
    }; 
    exports.age = age;  //等效于:  module.exports.age = age;
    exports.sayHelloTo=sayHelloTo;  //等效于: module.exports.sayHelloTo=sayHelloTo;

P.S.不能直接將exports指向一個值裹纳,這會切斷 exports 與 module.exports 的聯(lián)系(但是可以用module.exports來指向一個值)

//./MyModule.js
    var age = 7; 
    var sayHelloTo= function (name) { 
        return "hello " + name;
    }; 
    exports = age;  //不要這么干择葡。這么做會切斷exports與module.exports的聯(lián)系, require該文件會得到一個空對象
    module.exports = age; //這樣寫沒有問題剃氧,require該文件會得到一個值7

不同于CommonJS敏储,ES6使用 export 和 import 來導入、導出模塊

用 export 導出的模塊朋鞍,需要用 import 來進行導入已添,而不能用 require。
P.S.:export 命令規(guī)定的是對外的接口滥酥,必須與模塊內(nèi)部的變量建立一一對應的關系

const utils = {
    showSth : function(){
        console.log("showSth");
    },
    saySth : function(){
        console.log("saySth");
    }
}
//導出的3種方式
// 方式1更舞,這種方式在引用的時候需要這樣: import {m} from './utils.js';
export var m = utils; 
// 方式2,用大括號來導出變量恨狈,如果導出的變量有多個疏哗,則{變量1,變量2,變量3...返奉,變量N}贝搁。
//這種方式在引用的時候需要這樣: import {utils} from './utils.js';
export {utils}; 
// 方式3,這種方式在引用的時候需要這樣: import {myUtils} from './utils.js';
//在引用的地方芽偏,也可以直接指定別名雷逆,如:import {myUtils as utils} from './utils.js';
export {utils as myUtils}; 

export 和 export default

  1. export 和export default 均可用于導出(常量 | 函數(shù) | 文件 | 模塊)等。
  2. 可以在其他文件中通過 import+(常量 | 函數(shù) | 文件 | 模塊)名的方式污尉,將其導入膀哲,以便能夠進行使用。
  3. 在一個文件或者模塊中被碗,export某宪、import 可以有多個,但 export default 僅有一個锐朴。
const utils = {
    showSth : function(){
        console.log("showSth");
    },
    saySth : function(){
        console.log("saySth");
    }
}
const name = "my name is Artech";
export {name}; //命名導出
export {utils};

//對于命名方式導出的兴喂,在導入的時候必須使用相應對象的相同名稱
//引用的時候:
import {utils,name as myName} from './utils.js';
  1. 通過 export 方式導出,在導入時要用花括號{ }焚志;而通過 export default 方式導出的衣迷,則不需要:
//如通過 export default 導出
  export default utils;  
//則在使用的時候不用加花括號,且導入時的名字可以自定義酱酬,如:
  import myUtils from './utils.js';  //對于默認方式導出的壶谒,則導入的時候,名稱可以隨便取

//默認導出:不能使用 let膳沽,var 或 const 作為默認導出

import *

將一個js文件中定義的方法汗菜,模塊,對象等挑社,全部導出呵俏,一般結合別名使用,如:

//myModule.js
   export const fun1 = ()=>{}
   export const objInfo = {...};
//demo.js:引用mymODULE滔灶。JS
    import * as myAlias from './myModule';
    //fun1()和objInfo都是定義在myModule中的方法和對象
    myAlias.fun1();
    myAlias.objInfo;

補充:

1. 如果用export default導出普碎,然后用import * 引入
//myModule.js
   export default {
    fun1: ()=>{},
    objInfo: {
      aaa: 'sss1'
    },
  }
//demo.js:引用myModule.js
    import * as myAlias from './myModule';
    //fun1()和objInfo都是定義在myModule中的default的方法和對象
    myAlias.default.fun1();
    myAlias.default.objInfo;

本質(zhì)上,export default就是輸出一個叫做default的變量或方法录平,然后系統(tǒng)允許你為它取任意名字麻车。所以,下面的寫法是有效的斗这。

//demo.js:引用myModule.js
    import { default as myAlias } from './myModule';
    myAlias.fun1();
    myAlias.objInfo;

正是因為export default命令其實只是輸出一個叫做default的變量动猬,所以它后面不能跟變量聲明語句

// 正確
export var a = 1;

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

// 錯誤
export default var a = 1;

上面代碼中,export default a的含義是將變量a的值賦給變量default表箭。所以赁咙,最后一種寫法會報錯。

同樣地,因為export default命令的本質(zhì)是將后面的值彼水,賦給default變量崔拥,所以可以直接將一個值寫在export default之后。

// 正確
export default 42;

// 報錯
export 42;

2. export語句輸出的接口凤覆,與其對應的值是動態(tài)綁定關系链瓦,即通過該接口,可以取到模塊內(nèi)部實時的值盯桦。
//myModule.js
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
//demo.js:引用myModule.js
  import * as myAlias from './myModule';
  console.log(myAlias.foo); //bar
  setTimeout(() => {
    console.log(myAlias.foo); //baz
  },1000);

這一點與 CommonJS 規(guī)范完全不同慈俯。CommonJS 模塊輸出的是值的緩存,不存在動態(tài)更新


3. export 和 import 命令可以出現(xiàn)在模塊的任何位置拥峦,只要處于模塊頂層就可以贴膘。如果處于塊級作用域內(nèi),就會報錯略号,這是因為處于條件代碼塊之中步鉴,就沒法做靜態(tài)優(yōu)化了,違背了 ES6 模塊的設計初衷璃哟。
function foo() {
  export default 'bar' // SyntaxError
}
foo()

上面代碼中,export語句放在函數(shù)之中喊递,結果報錯随闪。


4. import命令輸入的變量都是只讀的,因為它的本質(zhì)是輸入接口骚勘。也就是說铐伴,不允許在加載模塊的腳本里面,改寫接口俏讹。
import {a} from './xxx.js'

a = {}; // Syntax Error : 'a' is read-only;

上面代碼中当宴,腳本加載了變量a,對其重新賦值就會報錯泽疆,因為a是一個只讀的接口户矢。但是,如果a是一個對象殉疼,改寫a的屬性是允許的梯浪。

import {a} from './xxx.js'

a.foo = 'hello'; // 合法操作

上面代碼中,a的屬性可以成功改寫瓢娜,并且其他模塊也可以讀到改寫后的值挂洛。不過,這種寫法很難查錯眠砾,建議凡是輸入的變量虏劲,都當作完全只讀,輕易不要改變它的屬性。


5. import命令具有提升效果柒巫,會提升到整個模塊的頭部励堡,首先執(zhí)行。
foo();

import { foo } from 'my_module';

上面的代碼不會報錯吻育,因為import的執(zhí)行早于foo的調(diào)用念秧。這種行為的本質(zhì)是,import命令是編譯階段執(zhí)行的布疼,在代碼運行之前摊趾。


6. 由于import是靜態(tài)執(zhí)行,所以不能使用表達式和變量游两,這些只有在運行時才能得到結果的語法結構砾层。
// 報錯
import { 'f' + 'oo' } from 'my_module';

// 報錯
let module = 'my_module';
import { foo } from module;

// 報錯
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}

上面三種寫法都會報錯,因為它們用到了表達式贱案、變量和if結構肛炮。在靜態(tài)分析階段,這些語法都是沒法得到值的宝踪。


7.import語句會執(zhí)行所加載的模塊侨糟,因此可以有下面的寫法。
import 'lodash';

上面代碼僅僅執(zhí)行lodash模塊瘩燥,但是不輸入任何值秕重。
如果多次重復執(zhí)行同一句import語句,那么只會執(zhí)行一次厉膀,而不會執(zhí)行多次溶耘。

import 'lodash';
import 'lodash';

上面代碼加載了兩次lodash,但是只會執(zhí)行一次服鹅。

import { foo } from 'my_module';
import { bar } from 'my_module';

// 等同于
import { foo, bar } from 'my_module';

上面代碼中凳兵,雖然foobar在兩個語句中加載,但是它們對應的是同一個my_module實例企软。也就是說庐扫,import語句是 Singleton 模式。


8.目前階段仗哨,通過 Babel 轉碼聚蝶,CommonJS 模塊的require命令和 ES6 模塊的import命令,可以寫在同一個模塊里面藻治,但是最好不要這樣做碘勉。因為import在靜態(tài)解析階段執(zhí)行,所以它是一個模塊之中最早執(zhí)行的桩卵。下面的代碼可能不會得到預期結果验靡。
require('core-js/modules/es6.symbol');
require('core-js/modules/es6.promise');
import React from 'React';

9. 如果想在一條import語句中倍宾,同時輸入默認方法和其他接口,可以寫成下面這樣胜嗓。
import _, { each, forEach } from 'lodash';

對應上面代碼的export語句如下高职。

export default function (obj) {}
export function each(obj, iterator, context) { }
export function forEach () { }

10. export default也可以用來輸出類。
// MyClass.js
export default class { ... }

// main.js
import MyClass from 'MyClass';
let o = new MyClass();

11. export 與 import 的復合寫法

如果在一個模塊之中辞州,先輸入后輸出同一個模塊怔锌,import語句可以與export語句寫在一起。

export { foo, bar } from 'my_module';

// 可以簡單理解為
import { foo, bar } from 'my_module';
export { foo, bar };

上面代碼中变过,exportimport語句可以結合在一起埃元,寫成一行。但需要注意的是媚狰,寫成一行以后岛杀,foobar實際上并沒有被導入當前模塊,只是相當于對外轉發(fā)了這兩個接口崭孤,導致當前模塊不能直接使用foobar类嗤。


未總結的:

模塊的繼承
跨模塊常量

如果要使用的常量非常多,可以建一個專門的constants目錄辨宠,將各種常量寫在不同的文件里面遗锣,保存在該目錄下。然后嗤形,將這些文件輸出的常量精偿,合并在index.js里面。

import() - 提案

importexport命令只能在模塊的頂層派殷,不能在代碼塊之中(比如,在if代碼塊之中墓阀,或在函數(shù)之中)毡惜。

這樣的設計,固然有利于編譯器提高效率斯撮,但也導致無法在運行時加載模塊经伙。在語法上,條件加載就不可能實現(xiàn)勿锅。如果import命令要取代 Node 的require方法帕膜,這就形成了一個障礙。因為require是運行時加載模塊溢十,import命令無法取代require的動態(tài)加載功能垮刹。

const path = './' + fileName;
const myModual = require(path);

上面的語句就是動態(tài)加載,require到底加載哪一個模塊张弛,只有運行時才知道荒典。import命令做不到這一點酪劫。

因此,有一個提案寺董,建議引入import()函數(shù)覆糟,完成動態(tài)加載。
.....

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遮咖,一起剝皮案震驚了整個濱河市滩字,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌御吞,老刑警劉巖麦箍,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異魄藕,居然都是意外死亡内列,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門背率,熙熙樓的掌柜王于貴愁眉苦臉地迎上來话瞧,“玉大人,你說我怎么就攤上這事寝姿〗慌牛” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵饵筑,是天一觀的道長埃篓。 經(jīng)常有香客問我,道長根资,這世上最難降的妖魔是什么架专? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮玄帕,結果婚禮上部脚,老公的妹妹穿的比我還像新娘。我一直安慰自己裤纹,他們只是感情好委刘,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鹰椒,像睡著了一般锡移。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上漆际,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天淆珊,我揣著相機與錄音,去河邊找鬼奸汇。 笑死套蒂,一個胖子當著我的面吹牛钞支,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播操刀,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烁挟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了骨坑?” 一聲冷哼從身側響起撼嗓,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎欢唾,沒想到半個月后且警,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡礁遣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年斑芜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祟霍。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡杏头,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沸呐,到底是詐尸還是另有隱情醇王,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布崭添,位于F島的核電站寓娩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏呼渣。R本人自食惡果不足惜棘伴,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屁置。 院中可真熱鬧焊夸,春花似錦、人聲如沸缰犁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帅容。三九已至,卻和暖如春伍伤,著一層夾襖步出監(jiān)牢的瞬間并徘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工扰魂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留麦乞,地道東北人蕴茴。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像姐直,于是被迫代替她去往敵國和親倦淀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354