在 es6 之前 JS 一直沒有自己的模塊語法,為了解決這種尷尬就有了require.js等AMD或CMD方式的出現。在 es6 發布之后 JS 又引入了 import 的概念使得不清楚兩者之間的區別的同學在實際使用過程中造成了自己的誤解,在查閱了相關資料之后在此記錄下自己的小小見解。
一、require 與 import 基本用法及引入方式區別
1、require的基本語法
核心概念:在導出的文件中定義 module.export,導出的對象的類型不予限定(可以是任何類型,字符串,變量,對象,方法),在引入的文件中調用 require() 方法引入對象即可。
//a.js中
module.export = { a: function(){ console.log(666) } } //b.js中
var obj = require('../a.js') obj.a() //666
本質上是將要導出的對象賦值給module這個的對象的export屬性,在其他文件中通過require這個方法訪問該屬性
require 的使用非常簡單,它相當於module.exports的傳送門,module.exports后面的內容是什么,require的結果就是什么,對象、數字、字符串、函數……再把require的結果賦值給某個變量,相當於把require和module.exports進行平行空間的位置重疊
require('./a')(); // a模塊是一個函數,立即執行a模塊函數
var data = require('./a').data; // a模塊導出的是一個對象
var a = require('./a')[0]; // a模塊導出的是一個數組
2、import的基本語法
核心概念:導出的對象必須與模塊中的值一一對應,換一種說法就是導出的對象與整個模塊進行解構賦值。抓住重點,解構賦值!
//a.js中 // 最常使用的方法,加入default關鍵字代表在import時可以使用任意變量名且不需要花括號{}
export default { a: function(){ console.log(666) } } export function(){ //導出函數 } export {newA as a ,b,c} // 解構賦值語法(as關鍵字在這里表示將newA作為a的數據接口暴露給外部,外部不能直接訪問a) //b.js中
import a from '...' //import常用語法(需要export中帶有default關鍵字)可以任意指定import的名稱
import {...} from '...' // 基本方式,導入的對象需要與export對象進行解構賦值。
import a as biu from '...' //使用as關鍵字,表示將a代表biu引入(當變量名稱有沖突時可以使用這種方式解決沖突)
import {a as biubiubiu,b,c} //as關鍵字的其他使用方法
二、require 與 import 主要區別
1、區別1:模塊加載的時間
require:運行時加載 —— require 是賦值過程,且是運行時才執行
import:編譯時加載(效率更高)—— import 是解構過程,且是編譯時執行
由於是編譯時加載,所以 import 命令會提升到整個模塊的頭部,下面代碼不會報錯,正常執行
test(); import { test} from '/test';
2、區別2:對性能的影響
require的性能相對於import稍低:因為 require 是在運行時才引入模塊,並且還賦值給某個變量;
而 import 只需要依據 import 中的接口在編譯時引入指定模塊,所以性能稍高。
3、區別3:模塊的本質
require:模塊就是對象,輸入時必須查找對象屬性
import:ES6 模塊不是對象,而是通過 export 命令顯式指定輸出的代碼,再通過 import 命令輸入(這也導致了沒法引用 ES6 模塊本身,因為它不是對象)。由於 ES6 模塊是編譯時加載,使得靜態分析成為可能。有了它,就能進一步拓寬 JavaScript 的語法,比如引入宏(macro)和類型檢驗(type system)這些只能靠靜態分析實現的功能。
// CommonJS模塊
let { exists, readFile } = require('fs'); // 等同於
let fs = require('fs'); let exists = fs.exists; let readfile = fs.readfile;
上面CommonJs模塊中,實質上整體加載了fs對象(fs模塊),然后再從fs對象上讀取方法
// ES6模塊
import { exists, readFile } from 'fs';
上面ES6模塊,實質上從fs模塊加載2個對應的方法,其他方法不加載
4、區別4:嚴格模式
CommonJs模塊和ES6模塊的區別:
(1)CommonJs模塊默認采用非嚴格模式
(2)ES6 的模塊自動采用嚴格模式,不管你有沒有在模塊頭部加上 “use strict”;
(3)CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用,舉例如下
// m1.js
export var foo = 'bar'; setTimeout(() => foo = 'baz', 500); // m2.js
import {foo} from './m1.js'; console.log(foo); //bar
setTimeout(() => console.log(foo), 500); //baz
在 commom.js 中 module.export 之后導出的值就不能再變化,但是在 es6 的 export 中是可以的。
var a = 6 export default {a} a = 7 //在es6中的export可以
var a = 6 module.export = a a = 7 //在common.js中,這樣是錯誤的
三、export導出模塊接口
1、在要導出的接口前面,加入export指令。
// a.js export default function() {} export function a () {} var b = 'xxx'; export {b}; // 這是ES6的寫法,實際上就是{b:b} setTimeout(() => b = 'ooo', 1000); export var c = 100;
2、錯誤演示
// 錯誤演示 export 1; // 絕對不可以 var a = 100; export a;
export 在導出接口的時候,必須與模塊內部的變量具有一一對應的關系。直接導出1沒有任何意義,也不可能在import的時候有一個變量與之對應。 export a
雖然看上去成立,但是 a
的值是一個數字,根本無法完成解構,因此必須寫成 export {a}
的形式。即使a被賦值為一個function,也是不允許的。而且,大部分風格都建議,模塊中最好在末尾用一個export導出所有的接口,例如:
export {fun as default,a,b,c};
3、S6中export及export default的區別
相信很多人都使用過 export、export default、import,然而它們到底有什么區別呢?
在JavaScript ES6中,export與export default均可用於導出常量、函數、文件、模塊等,你可以在其它文件或模塊中通過 import+(常量 | 函數 | 文件 | 模塊)名 的方式,將其導入,以便能夠對其進行使用,但在一個文件或模塊中,export、import 可以有多個,export default僅有一個。