走向Node與Webpack 之路 - CommonJS 模塊化

走向Node與Webpack 之路 - CommonJS 模塊化

1. 參考資料

JavaScript 標準參考教程(alpha)javascript

CommonJS規範(推薦 - 阮一峯寫的)html

官方網站 (看半天,不知道幹啥!)java

CommonJS 是什麼 ? (有些暈)node


2. 基本環境

  • node v4.5.0
  • npm v4.2.0

這裏基本環境安裝配置就不說了,本身查找資料。jquery

使用webstrom ,使用 node 記得enable ,寫相關命令的時候,纔會提醒顯示: 
如圖:個人是已經打開的webpack

這裏寫圖片描述


3. 認識

不管是node應用模塊,仍是webpack 配置 ,均是採用CommonJS模塊化規範。git

Example :github

example.jsweb

/** * Created by yuan on 2/21/2017. */ var x = 1; var addX = function (value) { return value + x; } module.exports.x = x; #對外提供值 module.exports.addX = addX; #對外提供函數

example-test.jsnpm

/** * Created by yuan on 2/21/2017. */ var example = require('./example.js') #加載模塊 console.log(example.x) #調用value console.log(example.addX(12)); #調用函數

執行 : node xxx.js 執行 js 文件

D:\webworkspace\webpack-demo\commond>node example1-test.js 1 13

規範:

  • 每一個js 文件就是一個模塊,有本身的做用域 ;
  • 每一個js 文件定義的函數,變量,類都是私有的;
  • 每一個模塊的運行,不會污染全局做用域 ;
  • 每一個模塊能夠屢次加載,但只會在第一次加載時運行一次,而後結果就緩存了;從新運行模塊,須要清除緩存;
  • 全部模塊的加載順序不定,按照被使用的順序加載;
  • require : 加載模塊
  • module.exports : 對外提供接口

3.module

全部的模塊都是一個module對象,表明當前模塊

Example : 
引入jquery , 打印當前module ;

  • npm install jquery -g : 安裝jquery
D:\webworkspace\webpack-demo\commond>npm install jquery -g C:\Users\yuan\AppData\Roaming\npm `-- jquery@3.1.1
  • 配置 package.json dependencies 依賴
"dependencies": { "jquery": "^3.1.1", }
  • example.js
/** * Created by yuan on 2/21/2017. */ var jquery= require('jquery'); exports.$ = jquery; console.log(module);
  • 執行
D:\webworkspace\webpack-demo\commond>node example2.js Module { id: '.', #模塊識別,一般是模塊的絕對路徑文件名 exports: { '$': [Function] },#模塊對外輸出的接口 parent: null, # 返回對象,表示調用該模塊的模塊 filename: 'D:\\webworkspace\\webpack-demo\\commond\\example2.js', # 絕對路徑的模塊名 loaded: false, # 表示是否加載完成 children: # 表示該模塊依賴的其餘模塊 [ Module { id: 'D:\\webworkspace\\webpack-demo\\node_modules\\jquery\\dist\\jquery.js', exports: [Function], parent: [Circular], filename: 'D:\\webworkspace\\webpack-demo\\node_modules\\jquery\\dist\\jquery.js', loaded: true, children: [], paths: [Object] } ], paths: [ 'D:\\webworkspace\\webpack-demo\\commond\\node_modules', 'D:\\webworkspace\\webpack-demo\\node_modules', 'D:\\webworkspace\\node_modules', 'D:\\node_modules' ] } 

(1)認識module

  • id : 模塊識別,一般是模塊的絕對路徑文件名
  • exports : 模塊對外輸出的接口
  • parent : 返回對象,表示調用該模塊的模塊
  • filename : 絕對路徑的模塊名
  • loaded : 表示是否加載完成
  • children : 表示該模塊依賴的其餘模塊

(2)module.exports

module.exports 當前模塊對外輸出的接口,對外提供變量;在每一個模塊中默認實現了

var exports=module.exports;

Example 1 :

/** * 返回x平方與y平方和 * @param x * @param y * @returns {number} */ function add(x, y) { return x * x + y * y; } // exports.add = add; // 對外提供add函數 // module.exports.add = add; //對外提供add函數 

結果:

上面兩種寫法,實現的效果是同樣的;建議使用 module.exports 來作,我以爲代碼清晰。

Example 2 :

//ok exports.hello = function () { console.log('hello node!') }; //error1 : 該exports 賦值 就和 module.exports 沒有了聯繫! exports = function (x) { console.log(x); }; //error2 : module.exports = 'hello commonJS';

結果:

注意: 不能夠對exports 或 module.exports 直接賦值,否則exports 就和 module 自己的exports 沒有關係了。


4. require

require 加載模塊文件: 讀入並執行javascript 文件 ,返回該module.exports對象

(1)簡單的加載

Example :

example.js

var sayHi = function (name) { console.log(name + ' say hi !'); console.log(require.main===module); #false }; module.exports.sayhi = sayHi;

example-test.js

var say = require('./example.js'); #加載上面的exmple.js console.log(say.sayhi('labelnet')); console.log(require.main === module); #true

執行

D:\webworkspace\webpack-demo\commond>node example4-test.js labelnet say hi ! false undefined true 

總結: 

require.main === module 能夠判斷模塊是直接執行的仍是被調用執行的,若是直接執行返回true , 被調用的返回false;

(2)require 加載規則

進行加載時,默認後綴名時 .js , 也就是說 require('./example4.js') 和 require('./example4') 效果實現同樣的。

參數格式:

參數格式決定了不一樣路徑尋找模塊文件

  • 「/」 開頭 , 絕對路徑加載
require('/yuan/dist/example.js')
  • 「.」 開頭 , 相對路徑加載,好比 同一目錄加載
require('./example4') require('./example4.js')
  • 「文件名稱」, 加載默認提供的核心模塊,package.json 以 配置的模塊,固然node_modules以安裝的工程
require('jquery')

(3)緩存

每一個模塊被加載時,只執行一次,其他的都去緩存中獲取;

requrie.cache

Example :

require('./example'); require('./example').message = 'hello js'; console.log(require('./example').message);

上面代碼,加載了三次example, 第二次添加message 變量,第三次打印message變量; 
結果:

D:\webworkspace\webpack-demo\commond>node example5-test.js hello js

說明 第三次的結果是從緩存中獲取的;

刪除緩存

刪除緩存,必須知道緩存模塊的絕對路徑,才能夠刪除; 
基本格式 :

delete require.cache[模塊絕對路徑];

Example :

require('./example'); require('./example').message = 'hello js'; // console.log(module); //能夠獲取到模塊的絕對路徑 delete require.cache['D:\\webworkspace\\webpack-demo\\commond\\example.js']; //刪除指定模塊緩存,緩存是根據絕對路徑識別的!! console.log(require('./example').message);

結果:

D:\webworkspace\webpack-demo\commond>node example5-test.js undefined

刪除所有緩存

Object.keys(require.cache).forEach(function (key) { delete require.cache[key]; });

5. 加載機制

(1)require 加載機制

對外輸出的值,是這個值得拷貝(複製),若是這個值內部值改變,那麼對外輸出的值並不改變;

Example : 
先打印外部值,改變內部值,再次打印外部值;

example.js

var value = 3; function add() { value++; console.log('內部 value +1 : ' + value) } module.exports = { value: value, add: add, };

example-test.js

/** * Created by yuan on 2/21/2017. */ var test= require('./exapmle6'); console.log('外部 value 執行1 : '+test.value); console.log(test.add()); console.log('外部 value 執行2 : '+test.value); 

結果:

D:\webworkspace\webpack-demo\commond>node example6-test.js
外部 value 執行1 : 3 內部 value +1 : 4 undefined 外部 value 執行2 : 3

(2)require 內部處理流程 (學習來源)

require 不是一個全局命令,而是指向當前模塊的module.require命令,然後者又調用Node的內部命令Module._load

Module._load = function(request, parent, isMain) { // 1. 檢查 Module._cache,是否緩存之中有指定模塊 // 2. 若是緩存之中沒有,就建立一個新的Module實例 // 3. 將它保存到緩存 // 4. 使用 module.load() 加載指定的模塊文件, // 讀取文件內容以後,使用 module.compile() 執行文件代碼 // 5. 若是加載/解析過程報錯,就從緩存刪除該模塊 // 6. 返回該模塊的 module.exports };

上面的第4步,採用 module.compile() 執行指定模塊的腳本,邏輯以下。

Module.prototype._compile = function(content, filename) { // 1. 生成一個require函數,指向module.require // 2. 加載其餘輔助方法到require // 3. 將文件內容放到一個函數之中,該函數可調用 require // 4. 執行該函數 };

上面的第1步和第2步,require函數及其輔助方法主要以下。

  • require(): 加載外部模塊
  • require.resolve():將模塊名解析到一個絕對路徑
  • require.main:指向主模塊
  • require.cache:指向全部緩存的模塊
  • require.extensions:根據文件的後綴名,調用不一樣的執行函數

一旦require函數準備完畢,整個所要加載的腳本內容,就被放到一個新的函數之中,這樣能夠避免污染全局環境。該函數的參數包括require、module、exports,以及其餘一些參數。

(function (exports, require, module, __filename, __dirname) { // YOUR CODE INJECTED HERE! });

Module._compile方法是同步執行的,因此Module._load要等它執行完成,纔會向用戶返回module.exports的值 。

 

轉自:https://blog.csdn.net/LABLENET/article/details/56287947

相關文章
相關標籤/搜索