NodeJS中的require和import

ES6標準發佈後,module成爲標準,標準的使用是以export指令導出接口,以import引入模塊,可是在咱們一向的node模塊中,咱們採用的是CommonJS規範,使用require引入模塊,使用module.exports導出接口。javascript

不把require和import整清楚,會在將來的標準編程中死的很難看。php

require時代的模塊

node編程中最重要的思想之一就是模塊,而正是這個思想,讓JavaScript的大規模工程成爲可能。模塊化編程在js界流行,也是基於此,隨後在瀏覽器端,requirejs和seajs之類的工具包也出現了,能夠說在對應規範下,require統治了ES6以前的全部模塊化編程,即便如今,在ES6 module被徹底實現以前,仍是這樣。java

node的module遵循CommonJS規範,requirejs遵循AMD,seajs遵循CMD,雖各有不一樣,但總之仍是但願保持較爲統一的代碼風格。node

// a.js

// -------- node ----------- module.exports = { a : function() {}, b : 'xxx' }; // ----------- AMD or CMD ---------------- define(function(require, exports, module){ module.exports = { a : function() {}, b : 'xxx' }; });

能夠看出,爲了保持風格的高度統一,除了在瀏覽器端的模塊中要使用一個define函數來提供模塊的閉包之外,其餘代碼能夠徹底一致。python

// b.js

// ------------ node --------- var m = require('./a'); m.a(); // ------------ AMD or CMD ------------- define(function(require, exports, module){ var m = require('./a'); m.a(); });

在使用上,也很是類似。雖然AMD or CMD提供了更加豐富的風格,可是咱們本文主要是討論node環境下,因此不作擴展。jquery

ES6中的module

ES6發佈的module並無直接採用CommonJS,甚至連require都沒有采用,也就是說require仍然只是node的一個私有的全局方法,module.exports也只是node私有的一個全局變量屬性,跟標準半毛錢關係都沒有。web

export導出模塊接口

export的用法挺複雜的,具體有哪些能夠看 這裏 。這裏舉幾個例子:typescript

// a.js
export default function() {} export function a () {} var b = 'xxx'; export {b}; // 這是ES6的寫法,實際上就是{b:b} setTimeout(() => b = 'ooo', 1000); export var c = 100;

在要導出的接口前面,加入export指令。編程

在export以後,b還能夠被修改,這和CommonJS有着巨大不一樣,關於內部機理的東西,本文就無恥的省略了。數組

注意,下面的語法有嚴重錯誤:

// 錯誤演示
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};

import導入模塊

import的語法跟require不一樣,並且import必須放在文件的最開始,且前面不容許有其餘邏輯代碼,這和其餘全部編程語言風格一致。

import的使用和export同樣,也挺複雜,能夠在 這裏 大體瞭解。舉幾個例子:

import $ from 'jquery'; import * as _ from '_'; import {a,b,c} from './a'; import {default as alias, a as a_a, b, c} from './a';

這裏有一些坑,暫時不透露,下面會講到。

import後面跟上花括號的形式是最基本的用法,花括號裏面的變量與export後面的變量一一對應。這裏,你必須瞭解 對象的解構賦值 的知識,沒這知識,你根本無法在這裏裝逼。瞭解瞭解構賦值,這裏的「一一對應」的關係就能具體理解了。

as關鍵字

編程的同窗對as都容易理解,簡單的說就是取一個別名。export中能夠用,import中其實能夠用:

// a.js
var a = function() {}; export {a as fun}; // b.js import {fun as a} from './a'; a();

上面這段代碼,export的時候,對外提供的接口是fun,它是a.js內部a這個函數的別名,可是在模塊外面,認不到a,只能認到fun。

import中的as就很簡單,就是你在使用模塊裏面的方法的時候,給這個方法取一個別名,好在當前的文件裏面使用。之因此是這樣,是由於有的時候不一樣的兩個模塊可能經過相同的接口,好比有一個c.js也經過了fun這個接口:

// c.js
export function fun() {};

若是在b.js中同時使用a和c這兩個模塊,就必須想辦法解決接口重名的問題,as就解決了。

default關鍵字

其餘人寫教程什麼的,都把default放到export那個部分,我以爲不利於理解。在export的時候,可能會用到default,說白了,它實際上是別名的語法糖:

// d.js
export default function() {} // 等效於: function a() {}; export {a as default};

在import的時候,能夠這樣用:

import a from './d'; // 等效於,或者說就是下面這種寫法的簡寫,是同一個意思 import {default as a} from './d';

這個語法糖的好處就是import的時候,能夠省去花括號{}。簡單的說,若是import的時候,你發現某個變量沒有花括號括起來(沒有*號),那麼你在腦海中應該把它還原成有花括號的as語法。

因此,下面這種寫法你也應該理解了吧:

import $,{each,map} from 'jquery';

import後面第一個 $ 是 {defalut as $} 的替代寫法。

*符號

*就是表明全部,只用在import中,咱們看下兩個例子:

import * as _ from '_';

在乎義上和 import _ from '_'; 是不一樣的,雖然實際上後面的使用方法是同樣的。它表示的是把 '_' 模塊中的全部接口掛載到 _ 這個對象上,因此能夠用 _.each調用某個接口。

另外還能夠經過*號直接繼承某一個模塊的接口:

export * from '_'; // 等效於: import * as all from '_'; export all;

*符號儘量少用,它其實是使用全部export的接口,可是頗有可能你的當前模塊並不會用到全部接口,可能僅僅是一個,因此最好的建議是使用花括號,用一個加一個。

該用require仍是import?

require的使用很是簡單,它至關於module.exports的傳送門,module.exports後面的內容是什麼,require的結果就是什麼,對象、數字、字符串、函數……再把require的結果賦值給某個變量,至關於把require和module.exports進行平行空間的位置重疊。

並且require理論上能夠運用在代碼的任何地方,甚至不須要賦值給某個變量以後再使用,好比:

require('./a')(); // a模塊是一個函數,當即執行a模塊函數 var data = require('./a').data; // a模塊導出的是一個對象 var a = require('./a')[0]; // a模塊導出的是一個數組

你在使用時,徹底能夠忽略模塊化這個概念來使用require,僅僅把它當作一個node內置的全局函數,它的參數甚至能夠是表達式:

require(process.cwd() + '/a');

可是import則不一樣,它是編譯時的(require是運行時的),它必須放在文件開頭,並且使用格式也是肯定的,無可置疑。它不會將整個模塊運行後賦值給某個變量,而是隻選擇import的接口進行編譯,這樣在性能上比require好不少。

從理解上,require是賦值過程,import是解構過程,固然,require也能夠將結果解構賦值給一組變量,可是import在遇到default時,和require則徹底不一樣: var $ = require('jquery'); 和 import $ from 'jquery' 是徹底不一樣的兩種概念。

上面徹底沒有回答「改用require仍是import?」這個問題,由於這個問題就目前而言,根本無法回答,由於目前全部的引擎都尚未實現import,咱們在node中使用babel支持ES6,也僅僅是將ES6轉碼爲ES5再執行,import語法會被轉碼爲require。這也是爲何在模塊導出時使用module.exports,在引入模塊時使用import仍然起效,由於本質上,import會被轉碼爲require去執行。

可是,咱們要知道這樣一個道理,ES7很快也會發布,js引擎們會盡快實現ES6標準的規定,若是一個引擎連標準都實現不了,就會被淘汰, ES6是早晚的事 。若是你如今仍然在代碼中部署require,那麼等到ES6被引擎支持時,你必須升級你的代碼,而若是如今開始部署import,那麼將來可能只須要作不多的改動。

 

總結:

1. require適用於導入遵循CommonJS規範模塊的場景, import 適用於導入ES6模塊的場景

2. 所謂CommonJS規範的模塊: 模塊使用 module.exports = ...., ES6模塊 export const A = 111 (如上文所說, export default A = 111 是const a = 11, export {default : a} 的語法糖實現)

3. require 是運行時的, import 是編譯時的, https://www.zhihu.com/question/56820346

相關文章
相關標籤/搜索