exports與module.exports還有import

由於JavaScript缺乏模塊體系,在ES6之前,社區指定了一些模塊加載方案,比如node.js所遵循的commonJS規範。而在ES6在語言層面上實現了模塊功能,完全可以取代現有的commonJS等規範,成爲瀏覽器、服務器通用的模塊解決方案。本篇博客目錄如下:
1.如何使用exports
2.如何使用module.exports
3.exports與module.exports的區別
4.使環境支持module語法
5.export與export default的基本用法

1.如何使用exports

在es6還沒有出現的日子裏,通過commonJS實現模塊加載會接觸到兩個方法,exports與module.exports。我們先來看exports,在node.js中,我們通常會以exports.name=something的形式來使用exports

//導出文件mout.js
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

exports.outputA=outputA;
exports.outputB=outputB;
//導入文件module.js
let mod=require("./mout.js");
console.log(mod);

這時會輸出
這裏寫圖片描述
如果你想在module.js中使用outputA或outputB函數,就得

let {outputA,outputB}=require("./mout.js");
//{}中變量名必須與mout.js導出函數名相同
outputA();
outputB();

上面的寫法也等同於

let _mout=require("./mout.js");
//變量a,b的變量名可以隨意
let a=_mout.outputA;
let b=_mout.outputB;
a();
b();

2.如何使用module.exports

在commonJS中還有一種方法可以導出模塊。我們通常以module.exports=something的形式使用它

//還是那個導出文件
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

module.exports=outputA;
module.exports=outputB;
//還是那個導入文件
let mod=require("./mout.js");
console.log(mod);

這個時候我們會發現輸出是這樣子的
這裏寫圖片描述
雖然我們在mout.js中module.exports兩次,但輸出卻告訴我們只有最後一次module.exports是有效的,第一次module.exports被覆蓋掉了。如果我們想在module.js中使用outputB只需mod()即可。
所以,當我們需要將模塊定義爲一個類時,使用module.exports是唯一的選擇

3.exports與module.exports的區別

其實,module.exports 初始值爲一個空對象 {}require() 返回的是 module.exports 而不是 exportsexports只不過是指向的 module.exports 的引用
賦給exports的所有屬性或方法最終都賦值給了module.exports。但,這是有前提條件的,那就是module.exports是空對象,如果module.exports具有了一些屬性或方法,那麼賦給exports的所有屬性或方法都會被忽略掉,譬如

//還是TA
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

exports.outputA=outputA;
module.exports=outputB;
//是TA是TA就是TA
let mod=require("./mout.js");
console.log(mod);

這樣子,輸出的就是醬紫的
這裏寫圖片描述
而且無論exports在module.exports前還是後,結果都是module.exports生效,而exports看起來並沒有發揮什麼卵用。
通過上面的推導,我們可以猜測給module.exports添加屬性等同於於給exports添加屬性

//。。。。。
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

module.exports.outputA=outputA;
module.exports.outputB=outputB;
//。。。。。
let mod=require("./mout.js");
console.log(mod);

直接看結果
這裏寫圖片描述
一目瞭然

4.使環境支持module語法

非常遺憾的是,到目前爲止,node(v9.3.0)尚不支持module語法,但不久後的將來是一定能夠實現的。爲了讓node等環境支持module語法,我們需要用到babel或者類似於babel的工具對代碼進行編譯。下面以babel爲主進行講解。
首先需要說明的是,如果你通過babel-node等工具試圖直接在命令行中運行es6代碼可能會出現錯誤。這是因爲

Babel默認只轉換新的JavaScript句法(syntax),而不轉換新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(比如Object.assign)都不會轉碼。而且像import和export這兩個命令現在在任何瀏覽器中都是不支持的, 同時babel也無法將其轉換爲瀏覽器支持的ES5, 原因在於:babel只是個翻譯,假設a.js 裏 import 了 b.js, 對a.js進行轉碼,只是翻譯了a.js,並不會把b.js的內容給讀取合並進來, 如果想在最終的某一個js裏,包含 a.js,b.js 的代碼,那就需要用到打包工具

接下來就以webpack爲例展示如何進行轉碼
首先,你得有個目錄,並且你安裝了node與npm
進入到目錄中,運行npm init
init完了之後,執行npm install webpack --save-dev --no-optional
接下來,你需要安裝babel-loader與babel-core

npm install --save-dev --no-optional babel-loader babel-core

然後根據你的需求選擇轉碼規則,目前有這些
這裏寫圖片描述
我們使用latest吧,npm install --save-dev --no-optional babel-preset-latest
之後我們還會用到path,所以一併安裝上npm install --save-dev --no-optional path
目前爲止,目錄下的webpack.config.js應該是醬紫的
這裏寫圖片描述

這一堆工作做完之後,我們還需要在根目錄下創建一個webpack配置文件——webpack.config.js,具體內容如下

const path=require("path");
module.exports = {
  entry:  __dirname + "/app/import.js",//入口文件
  output: {
    path: __dirname + "/dist",//打包後的文件存放的地方
    filename: "bundle.js"//打包後輸出文件的文件名
  },
  module:{
    loaders:[
        {
            test:/\.js$/,
            loader:'babel-loader',//-loader不可省略
            include:path.resolve(__dirname,'/app'),//babel只處理指定目錄
            options:{
                presets:['latest']
            }
        }
    ]
  }
}

其中,options字段值得我們注意。一般來說babel有三種配置方式:
通過webpack.config.js loaders中的options字段
通過package.json中的babel字段
通過.babelr文件
三種方式具體的配置內容是一模一樣的,我比較喜歡第一種

這樣子一通折騰下來後,我們在app下創建兩個文件import.js與export.js。

//import.js
import {alias,outputB} from "./export.js"
console.log(alias);
console.log(outputB);
//export.js
function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA as alias,outputB}

之後在根目錄下運行webpack,等待打包完成之後,在dist目錄下就會出現bundle.js,我們通過html引用也好,還是直接node運行都可以,輸出結果是
這裏寫圖片描述

5.export與export default的基本用法

普通的、老老實實的、樸實無華的操作

function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA,outputB}
import {outputA,outputB} from "./export.js"
outputA()

在引入文件中,如果需要使用export.js中的函數,用戶必須先知道它的名字,如果用戶不想翻文檔或者怎麼滴,這樣子就不太方便,所以就有了export default

function outputA(){
    console.log("this is output A");
}

export default outputB;
import alias from "./export.js"
console.log(alias);
alias();

注意,在import的時候,我們已經不用使用{}了
模塊整體加載
如果我們需要加載模塊的全部接口,那麼只需

function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA,outputB}
import * as alias from "./export.js"

export時使用別名

function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA as alias,outputB}

接下來,我們進行一些比較騷氣的操作

function outputA(){
    console.log("this is output A");
}

function outputB(){
    console.log("this is output B");
}

export {outputA as alias,outputB}
export default outputB;

這段代碼既有export又有export default
我們先

import * as x from "./export.js"
console.log(x);

這是,console出來的x是
這裏寫圖片描述
這裏我們可以看出export default的本質是輸出一個叫做default的方法,系統允許我們對它取任意名稱
接下來,醬紫

import x from "./export.js"
console.log(x);

輸出結果是
這裏寫圖片描述
也就是說,如果import時變量只有一個,而且外面沒有{},那麼該變量接受的就是export default。如果import時變量放在{}裏,那麼就會拿到對應的export。我們可以用這種方式同時接受export與export default

import x,{alias,outputB} from "./export.js"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章