當import/export、require/module.exports 混用時, 你能分清嗎?

ES6的模塊化: import export default

common.js的模塊化: require module.exports node.js使用該規(guī)范

為什么有模塊概念

理想情況下,開發(fā)者只需要實現(xiàn)核心的業(yè)務邏輯,其他都可以加載別人已經(jīng)寫好的模塊。

但是,Javascript不是一種模塊化編程語言,在es6以前,它是不支持”類”(class),所以也就沒有”模塊”(module)了。同時以前也沒有webpack這樣的工具,可以使用node去操作文件,讀取文件內容, 然后達到引入文件內容的目的.(也就是模塊化)--在不同的文件中放著不同的功能模塊

Common.js

首先需要明白的在node中每個文件都是一個自執(zhí)行函數(shù)(只不過我們肉眼凡胎看不出來,哈啊哈)

(function (exports, require, module, __filename, __dirname) {
    module.exports = exports = this
    return module.exports
})()

為了說明module.exports = exports = this請看下面例子

a.js

this.a = 123  // 第一種
exports.a = 123   //第二種
module.exports.a = 123  // 第三種

b.js

let a = require('./a')
console.log(a)

效果:


image

ES6中的模塊化

import/export

export defaultexport 的區(qū)別

  1. 在一個文件或模塊中 export 可以有多個,但 export default 僅有一個
  2. 通過 export 方式導出,在導入時要加 { },而 export default 則不需要
1.export
//a.js
export const str = "小生方勤";
//b.js
import { str } from 'a';   // 導入的時候需要花括號

2.export default
//a.js
const str = "小生方勤";
export default str;
//b.js
import str from 'a';      // 導入的時候無需花括號

export default const a = 1; 這樣寫是會報錯的喲。

es6 的導出模塊寫法有

export default 123;

export const a = 123;

const b = 3;
const c = 4;
export { b, c };

雖然我們一般在像Vue一些框架中都可以使用Es6的語法進行導入導出,但是babel 會將這些統(tǒng)統(tǒng)轉換成 commonjs 的 exports。

exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.c = 4;
exports.__esModule = true;

babel 轉換 es6 的模塊輸出邏輯非常簡單,即將所有輸出都賦值給 exports,并帶上一個標志 __esModule 表明這是個由 es6 轉換來的 commonjs 輸出。

babel將模塊的導出轉換為commonjs規(guī)范后,也會將引入 import 也轉換為 commonjs 規(guī)范。即采用 require 去引用模塊,再加以一定的處理,符合es6的使用意圖。

也就是所有最后通過webpack打包后都將轉化為common.js的規(guī)范

引入 default

對于最常見的

import a from './a.js';

在es6中 import a from './a.js' 的本意是想去引入一個 es6 模塊中的 default 輸出。

通過babel轉換后得到 var a = require(./a.js) 得到的對象卻是整個對象,肯定不是 es6 語句的本意,所以需要對 a 做些改變。

我們在導出提到,default 輸出會賦值給導出對象的default屬性。

exports.default = 123;

所以這里最后的 a 變量就是 require 的值的 default 屬性。如果原先就是commonjs規(guī)范的模塊,那么就是那個模塊的導出對象。

引入 * 通配符

我們使用 import * as a from './a.js' es6語法的本意是想將 es6 模塊的所有命名輸出以及defalut輸出打包成一個對象賦值給a變量。

已知以 commonjs 規(guī)范導出:

exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.__esModule = true;

那么對于 es6 轉換來的輸出通過 var a = require('./a.js') 導入這個對象就已經(jīng)符合意圖。

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

import { a } from './a.js'
直接轉換成 require('./a.js').a 即可。

總結

經(jīng)過上面的轉換分析,我們得知即使我們使用了 es6 的模塊系統(tǒng),如果借助 babel 的轉換,es6 的模塊系統(tǒng)最終還是會轉換成 commonjs 的規(guī)范。所以我們如果是使用 babel 轉換 es6 模塊,混合使用 es6 的模塊和 commonjs 的規(guī)范是沒有問題的,因為最終都會轉換成 commonjs。

問題

為何有的地方使用 require 去引用一個模塊時需要加上 default?

require('xx').default

我們在上文 babel 對導出模塊的轉換提到,es6 的 export default 都會被轉換成 exports.default,即使這個模塊只有這一個輸出。

我們經(jīng)常會使用 es6 的 export default 來輸出模塊,而且這個輸出是這個模塊的唯一輸出,我們會誤以為這種寫法輸出的是模塊的默認輸出。

// a.js

export default 123;
// b.js 錯誤

var foo = require('./a.js')

在使用 require 進行引用時,我們也會誤以為引入的是a文件的默認輸出。

結果這里需要改成 var foo = require('./a.js').default

這個場景在寫 webpack 代碼分割邏輯時經(jīng)常會遇到。

require.ensure([], (require) => {
   callback(null, [
     require('./src/pages/profitList').default,
   ]);
 });

模塊依賴的優(yōu)化


模塊依賴的優(yōu)化

我們在使用各大 UI 組件庫時都會被介紹到為了避免引入全部文件,請使用 babel-plugin-component 等babel 插件。

import { Button, Select } from 'element-ui'

由前文可知 import 會先轉換為 commonjs, 即

var a = require('element-ui');
var Button = a.Button;
var Select = a.Select;

var a = require('element-ui'); 這個過程就會將所有組件都引入進來了。

所以 babel-plugin-component就做了一件事,將 import { Button, Select } from 'element-ui' 轉換成了

import Button from 'element-ui/lib/button'
import Select from 'element-ui/lib/select'

即使轉換成了 commonjs 規(guī)范,也只是引入自己這個組件的js,將引入量減少到最低。

所以我們會看到幾乎所有的UI組件庫的目錄形式都是

|-lib
||--component1
||--component2
||--component3
|-index.common.js

index.common.jsimport element from 'element-ui' 這種形式調用全部組件

給個element的鏈接去看看吧 :https://element.eleme.cn/#/zh-CN/component/quickstart

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容