Javascript自誕生以來,曾經沒有人拿它當做一門程式語言。在Web 1.0時代,這種腳本語言主要被用來做表單驗證和網頁特效。直到Web 2.0時代,前端工程師利用它大大提升了網頁上的使用者體驗,JS才被廣泛重視。在JS逐漸流行的過程中,它大致經歷了工具類別庫、元件庫、前端框架、前端應用的變化。 Javascript先天缺乏一項功能:模組,而CommonJS規範的出現則彌補了這個缺陷。本文將介紹CommonJS規格及Node的模組機制。
在其他高階語言中,Java有類別文件,Python有import機制,PHP有include和require。而JS透過<script>標籤引入程式碼的方式顯得雜亂無章。過去人們不得不用命名空間等方式來人為地約束程式碼,直到CommonJS規格的出現,前後端的Javascript才得以實現大一統。 Node借鑒了CommonJS的Modules規格實作了一套非常易用的模組系統。 </script>
1. CommonJS模組規格
CommonJS的模組規格分為3個部分:
1).模組引用:透過require()方法並傳入一個模組標識來引入一個模組的API到當前上下文中,如var math = require('math');
2).模組定義:透過exports物件來導出目前模組的方法或變數。模組中還存在一個module對象,exports其實是module的屬性。在Node中,一個檔案就是一個模組,模組內的「全域變數」對外都不可見,只有掛載在exports上的屬性才是公開的,如exports.add = function() {}; exports.PI = 3.1415926;
3).模組標識:實際上就是傳遞給require()的參數,如上述的'math',它必須是符合camel命名法的字串,或者是以“.”“..”開頭的相對路徑或絕對路徑,它可以沒有檔名後綴“.js”
2. Node模組實作過程
在Node中,模組分為兩類:一類是Node本身提供的核心模組,另一類是使用者自己寫的檔案模組。核心模組有一部分在Node原始碼的編譯過程中,編譯成了二進位文件,在Node啟動時核心模組就被直接載入進記憶體中,所以它的載入速度是最快的。文件模組則是在運行時動態加載,需要經歷三個步驟:路徑分析,文件定位,編譯執行。請注意,Node對引入過的模組都會進行緩存,以減少二次引入時的開銷,並對相同模組的二次加載都採用最優先從緩存加載的策略。
2.1 路徑分析
路徑分析主要分析上述提到的模組標識符,主要分為以下幾類:
1)、核心模組,如http、fs、path等
2)、.或..開始的相對路徑檔模組
3)、以/開始的絕對路徑檔模組
4)、自訂檔案模組,可能是一個檔案或套件的形式。 Node會根據模組路徑數組module.paths來逐一嘗試查找目標文件,通常是沿著當前目錄逐級向上直到根目錄查找名為node_modules的目錄,所以這是查找最費時的一種方式。
2.2 檔案定位
在路徑分析的基礎上,檔案定位需要注意以下細節:
1)、檔案副檔名分析:由於CommonJS規格允許模組識別不填入副檔名,Node會按.js、.json、.node的次序不足副檔名,依序嘗試
2)、目錄分析和套件:若經過上述文件副檔名分析後沒有查找到對應文件,卻得到一個目錄,Node會把目錄當作一個包來處理
2.3 編譯執行
定位到特定檔案後,Node會新建一個模組對象,依照路徑載入並編譯。對於不同的副檔名,載入方法有所不同:
1)、.js檔:透過fs模組同步讀取檔並編譯執行
2)、.node檔:這是用C/C 寫的擴充文件,透過dlopen()方法載入
3)、.json檔:透過fs模組同步讀取文件,用JSON.parse()解析回傳結果
4)、其餘副檔名檔:都被當做.js檔載入
我們知道每個模組檔案中預設都存在著require、exports、module這3個變量,甚至在Node的API文件中,我們知道每個模組還有filename、dirname這2個變數的存在,它們是從何而來的呢? Node的模組又是怎麼做到宣告的「全域變數」其實是不會污染到其他模組的?事實上,Node在編譯JS模組過程中會對檔案內容進行頭尾包裝。下面是一個JS檔案經過頭尾包裝的範例:
(function(exports, require, module, __filename, __dirname) {
/* 中間是JS檔案的實際內容 */
var math = require('math');
exports.area = function(radius) {
return Math.PI * radius * radius;
};
/* JS檔案的實際內容結束 */
});
這樣每個模組檔案之間都進行了作用域隔離,同時require、exports、module等變數也被注入到了模組的上下文當中。這就是Node對CommonJS模組規範的實作。關於C/C 模組及Node核心模組的編譯過程較為複雜,不再贅述。
3. 模組呼叫堆疊
有必要先明確Node中各種模組的呼叫關係,如下圖所示:
C/C 內建模區塊是最底層的模組,屬於核心模組,主要提供API給Javascript核心模組和第三方Javascript檔案模組調用,實際上幾乎不會接觸到此類模組。 Javascript核心模組主要職責有兩種:一種是作為C/C 內建模塊的封裝層和橋接層供文件模組調用,另一種是純粹的功能模組,不需要跟底層打交道。文件模組通常由第三方編寫,包括普通Javascript模組和C/C 擴充模組。
4. 包與NPM
4.1 套件結構
套件本質上是一個存檔檔案(一般為.zip或.tar.gz),安裝後解壓縮還原為目錄。 CommonJS的包規格由包結構和包描述文件兩部分組成。一個完全符合CommonJS規範的套件結構應包含以下檔案:
1).package.json:套件描述檔
2).bin:存放可執行二進位的目錄
3).lib:存放Javascript程式碼的目錄
4).doc:存放文件的目錄
5).test:存放單元測試用例的目錄
4.2 包裝描述檔
套件描述檔是一個JSON檔案-package.json,位於套件的根目錄下,是套件的重要組成部分,用於描述套件的概況資訊。後面要提到的NPM的所有行為都與這個文件的欄位息息相關。以下將以知名Web框架express專案的package.json檔案為例說明一些常用欄位的意義。
1).name:包名
2).description:包簡介
3).version:版本號,需遵照“語意化的版本控制”,參考http://semver.org/
4).dependencies:使用目前套件所需依賴的套件清單。這個屬性十分重要,NPM會透過這個屬性自動載入依賴的套件
5).repositories:託管原始碼的位置清單
其餘欄位的用法可以參考NPM package.json說明
4.3 NPM常用功能
NPM(node package manager),通常稱為node套件管理器。它的主要功能是管理node包,包括:安裝、解除安裝、更新、檢視、搜尋、發布等。
4.3.1 NPM套件安裝
Node包的安裝分為兩種:本機安裝、全域安裝。兩者的差異如下:
1).本機安裝npm install
2).全域安裝npm install -g
4.3.2 NPM套件管理
以下以grunt-cli(grunt命令列工具)為例,列出常用的套件管理指令:
1).npm install:安裝package.json檔案的dependencies和devDependencies欄位宣告的所有套件
2).npm install grunt-cli@0.1.9:安裝特定版本的grunt-cli
3).npm install grunt-contrib-copy --save:安裝grunt-contrib-copy,同時保存該依賴到package.json檔案
4).npm uninstall grunt-cli:卸載套件
5).npm list:查看安裝了哪些套件
6).npm publish

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。