對於模塊加載:ES6、CommonJS、AMD、CMD的區別


運行和編譯的概念

編譯包括編譯和鏈接兩步。

編譯,把源代碼翻譯成機器能識別的代碼或者某個中間狀態的語言。

比如java只有JVM識別的字節碼,C#中只有CLR能識別的MSIL。還簡單的作一些比如檢查有沒有粗心寫錯啥關鍵字了啊.有啥詞法分析,語法分析之類的過程。

鏈接,是把編譯生成的二進制文件,組合成為一個系統可以執行的可執行文件。

 

運行:

把編譯出來的可執行文件代碼在系統中執行的過程,此時被裝載到內存中

(代碼保存在磁盤上沒裝入內存之前是個死家伙.只有跑到內存中才變成活的).

運行時類型檢查就與前面講的編譯時類型檢查(或者靜態類型檢查)不一樣.不是簡單的掃描代碼.而是在內存中做些操作,做些判斷.

模塊的加載

ES6、CommonJS、AMD、CMD指的都是一種規范。

CommonJS

為在瀏覽器環境之外構建JavaScript生態系統而產生的項目,比如服務器和桌面環境中。

一個單獨的文件就是一個模塊,代碼都運行在模塊作用域,如果想在多個文件分享變量,必須定義為global對象的屬性。(不推薦)

//模塊內部,module變量代表當前模塊,它的exports屬性是對外的接口
//其他文件加載該模塊,實際上就是讀取module.exports變量。
var x = 5;
var addX = function (value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
//PS:不能直接對module.exports賦值,只能給它添加方法或者屬性

加載機制:

模塊可多次加載,但模塊的運行只在第一次加載時,運行結果被緩存了,以后再加載,就直接讀取緩存結果。

通過require()同步加載依賴,導出API輸出到當前模塊,多個模塊不能並行加載。

輸入的是值的拷貝。也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值

應用:

服務器端的Node.js遵循CommonJS規范,Node.js主要用於服務器的編程,加載的模塊文件一般都已經存在本地硬盤,所以加載起來比較快,不用考慮異步加載的方式,所以CommonJS規范比較適用。

 

如果是瀏覽器環境,要從服務器加載模塊,這是就必須采用異步模式。所以就有了 AMD 、CMD 的解決方案,AMD與CMD都借鑒了CommonJs

AMD 、CMD

AMD(Asynchronous Module Definition)異步模塊加載,AMD 里,require 分全局 require 和局部 require。

CMD(Common Module Definition) 通用模塊加載,提供模塊定義及按需執行模塊。CMD 里,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啟動

優劣:

AMD | 速度快 | 會浪費資源 | 預先加載所有的依賴,直到使用的時候才執行
CMD | 只有真正需要才加載依賴 | 性能較差 | 直到使用的時候才定義依賴

AMD:

define(['./a', './b'], function(a, b) { //運行至此,a.js和b.js文件已下載完成 a模塊和b模塊已執行完,直接可用;
    a.doing();
    // 此處省略500行代碼
    b.doing();
});

CMD:

define(function(require, exports, module) {
     var a = require("./a"); //等待a.js下載、執行完
     a.doing();
     // 此處省略500行代碼
     var b = require("./b"); //依賴就近書寫
     b.doing();
});

 ES6

使用export或export default導出,import導入。

import是編譯時調用,所以不能使用表達式和變量,這些只有在運行時才能得到結果的語法結構。

import是解構過程,本質是輸入接口,不允許在加載模塊的腳本里面,改寫接口。

import命令具有提升效果,會提升到整個模塊的頭部,首先執行。

import語句會執行所加載的模塊,因此可以有下面的寫法。

import 'lodash';

上面代碼僅僅執行lodash模塊,但是不輸入任何值。

多次重復執行同一句import語句,那么只會執行一次。

 

在一個模塊之中,先輸入后輸出同一個模塊,export和import語句可以結合在一起,寫成一行:

export { foo, bar } from 'my_module';

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

注意的是,foobar實際上並沒有被導入當前模塊,只是相當於對外轉發了這兩個接口,導致當前模塊不能直接使用foobar

export與export default的區別:

1.export與export default均可用於導出常量、函數、文件、模塊等
2.在一個文件或模塊中,export、import可以有多個,export default僅有一個
3.通過export方式導出,在導入時要加{ },export default則不需要

4. 

(1)模塊輸出單個值,使用export default

(2) 模塊輸出輸出多個值,使用export

(3) export default與普通的export不要同時使用

//a.js  export
export const str = "blablabla~";
export function log(sth) { 
  return sth;
}

//b.js  import
import { str, log } from 'a'; //也可以分開寫兩次,導入的時候帶花括號


//a.js  export default
const str = "blablabla~";
export default str;


//b.js  import
import str from 'a'; //導入的時候沒有花括號

//本質上,a.js文件的export default輸出一個叫做default的變量,然后系統允許你為它取任意名字。所以可以為import的模塊起任何變量名,且不需要用大括號包含

import和require的區別

vue模塊引入使用import,node模塊引入使用require

遵循規范

  • require 是 AMD規范引入方式
  • import是es6的一個語法標准,如果要兼容瀏覽器的話必須轉化成es5的語法(最好去看文檔

加載

  • require是運行時調用在運行時確定模塊的依賴關系,得到模塊對象及輸入/輸出的變量,無法進行靜態優化。所以require的是運行的結果,把結果賦值給某個變量。
    1. 通過require引入基礎數據類型時,屬於復制該變量。
    2. 通過require引入復雜數據類型時,數據淺拷貝該對象。
  • import是編譯時調用,支持編譯時靜態分析,不需要的方法就不會加載,便於JS引入宏和類型檢驗,不能包含運行才知道結果的表達式等

寫法

require / exports :

const fs = require('fs')
exports.fs = fs
module.exports = fs

import / export:

import fs from 'fs'
import {default as fs} from 'fs'
import * as fs from 'fs'
import {readFile} from 'fs'
import {readFile as read} from 'fs'
import fs, {readFile} from 'fs'

export default fs
export const fs
export function readFile
export {readFile, read}
export * from 'fs'

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM