本篇文章為大家帶來了關於javascript中的相關知識,其中主要介紹了模組化程式設計規範,CommonJS、AMD、CMD以及ES6的相關問題,希望對大家有幫助。
相關推薦:javascript學習教學
#一、前言
AMD、 CMD、CommonJs
是ES5
中提供的模組化程式設計方案,import/export
是ES6
新增的模組化程式設計方案。
那麼,究竟什麼是AMD、CMD、CommonJs
?他們之間又存在什麼差別呢?專案開發應該選用哪一種模組化程式設計規範,又是如何使用?本篇部落格文章將一一解答以上疑問。
二、AMD-非同步模組定義
AMD
是」Asynchronous Module Definition
」的縮寫,即」非同步模組定義」。它採用非同步方式載入模組,模組的載入不影響它後面語句的運作。
這裡異步指的是不堵塞瀏覽器其他任務(dom
構建,css
渲染等),而加載內部是同步的(加載完模組後立即執行回調)。
RequireJS
:是一個AMD
框架,可以非同步載入JS
文件,依照模組載入方法,透過define()函數定義,第一個參數是數組,裡面定義一些需要依賴的包,第二個參數是一個回調函數,透過變數來引用模組裡面的方法,最後透過return來輸出。
AMD
是RequireJS
在推廣過程中對模組定義的規範化產出,它是一個概念,RequireJS
是對這個概念的實現,就好比JavaScript
語言是對ECMAScript
規範的實作。 AMD
是一個組織,RequireJS
是在這個組織下自訂的一套腳本語言。
不同於CommonJS
,它要求兩個參數:
require([module], callback);
第一個參數[module]
,是數組,裡面的成員是要載入的模組,callback
是載入完成後的回呼函數。如果將上述的程式碼改成AMD
方式:
require(['math'], function(math) { math.add(2, 3);})
其中,回呼函數中參數對應數組中的成員(模組)。
requireJS
載入模組,採用的是AMD
規格。也就是說,模組必須按照AMD
規定的方式來寫。
具體來說,就是模組書寫必須使用特定的define()
函數來定義。如果一個模組不依賴其他模組,那麼可以直接寫在define()
函數之中。
define(id, dependencies, factory);
id
:模組的名字,如果沒有提供該參數,模組的名字應該預設為模組載入器請求的指定腳本名字;dependencies
:模組的依賴,已被模組定義的模組標識的陣列字面量。依賴參數是可選的,如果忽略此參數,它應該預設為["require", "exports", "module"]
。然而,如果工廠方法的長度屬性小於3,載入器會選擇以函數的長度屬性指定的參數個數呼叫工廠方法。factory
:模組的工廠函數,模組初始化要執行的函數或物件。如果為函數,它應該只被執行一次。如果是對象,此對象應該為模組的輸出值。
假定現在有一個math.js
文件,定義了一個math
模組。那麼,math.js
書寫方式如下:
// math.jsdefine(function() { var add = function(x, y) { return x + y; } return { add: add }})
載入方法如下:
// main.jsrequire(['math'], function(math) { alert(math.add(1, 1));})
如果math
模組也依賴其他模組,寫法如下:
// math.jsdefine(['dependenceModule'], function(dependenceModule) { // ...})
當require()
函數載入math
模組的時候,就會先載入dependenceModule
模組。當有多個依賴時,就將所有的依賴都寫在define()
函數第一個參數數組中,所以說AMD
是依賴前置的。這不同於CMD
規範,它是依賴就近的。
CMD
三、CMD-同步模組定義
CMD
即Common Module Definition
通用模組定義,是SeaJS
在推廣過程中對模組定義的規範化產出,是一個同步模組定義,是SeaJS
的一個標準,SeaJS
是CMD
概念的一個實現,SeaJS
是淘寶團隊玉伯提供的一個模組開發的js
框架。 CMD
規格是國內發展出來的,就像AMD
有個requireJS
,CMD
有個瀏覽器的實作SeaJS
,SeaJS
要解決的問題和requireJS
一樣,只不過在模組定義方式和模組載入(可以說運行、解析)時機上有所不同。
CMD
通过define()
定义,没有依赖前置,通过require
加载jQuery
插件,CMD
是依赖就近,在什么地方使用到插件就在什么地方require
该插件,即用即返,这是一个同步的概念。
在 CMD
规范中,一个模块就是一个文件。代码的书写格式如下:
define(function(require, exports, module) { // 模块代码});
其中,
require
是可以把其他模块导入进来的一个参数;exports
是可以把模块内的一些属性和方法导出的;module
是一个对象,上面存储了与当前模块相关联的一些属性和方法。
AMD
是依赖关系前置,在定义模块的时候就要声明其依赖的模块;CMD
是按需加载依赖就近,只有在用到某个模块的时候再去require
,示例代码如下:
// CMDdefine(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... })// AMD 默认推荐的是define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ...})
四、CommonJS 规范
CommonJS
规范是通过module.exports
定义的,在前端浏览器里面并不支持module.exports
,通过node.js
后端使用。Nodejs
端使用CommonJS
规范,前端浏览器一般使用AMD
、CMD
、ES6
等定义模块化开发规范。
CommonJS
的终极目标是提供一个类似Python
,Ruby
和Java
的标准库。这样的话,开发者可以使用CommonJS API
编写应用程序,然后这些应用就可以运行在不同的JavaScript
解释器和不同的主机环境中。
在兼容CommonJS
的系统中,你可以使用JavaScript
开发以下程序:
- 服务器端
JavaScript
应用程序;- 命令行工具;
- 图形界面应用程序;
- 混合应用程序(如,Titanium或Adobe AIR);
2009年,美国程序员Ryan Dahl创造了node.js
项目,将javascript
语言用于服务器端编程。这标志"Javascript
模块化编程"正式诞生。NodeJS
是CommonJS
规范的实现,webpack
也是以CommonJS
的形式来书写。
node.js
的模块系统,就是参照CommonJS
规范实现的。在CommonJS
中,有一个全局性方法require()
,用于加载模块。假定有一个数学模块math.js
,就可以像下面这样加载。
var math = require('math');
然后,就可以调用模块提供的方法:
var math = require('math');math.add(2,3); // 5
CommonJS
定义的模块分为:模块引用(require)、 模块定义(exports)、模块标识(module)。
其中,
require()
用来引入外部模块;exports
对象用于导出当前模块的方法或变量,唯一的导出口;module
对象就代表模块本身。
虽说NodeJS
遵循CommonJS
的规范,但是相比也是做了一些取舍,添了一些新东西的。
NPM
作为Node
包管理器,同样遵循CommonJS
规范。
下面讲讲commonJS
的原理以及简易实现:
1、原理
浏览器不兼容CommonJS
的根本原因,在于缺少四个Node.js
环境变量。
module exports require global
只要能够提供这四个变量,浏览器就能加载 CommonJS
模块。
下面是一个简单的示例。
var module = { exports: {}};(function(module, exports) { exports.multiply = function (n) { return n * 1000 }; }(module, module.exports))var f = module.exports.multiply; f(5) // 5000
上面代码向一个立即执行函数提供 module 和 exports 两个外部变量,模块就放在这个立即执行函数里面。模块的输出值放在 module.exports 之中,这样就实现了模块的加载。
2、Browserify 的实现Browserify
是目前最常用的 CommonJS
格式转换工具。
请看一个例子,main.js
模块加载 foo.js
模块。
// foo.jsmodule.exports = function(x) { console.log(x);};// main.jsvar foo = require("./foo");foo("Hi");
使用下面的命令,就能将main.js
转为浏览器可用的格式。
$ browserify main.js > compiled.js
其中,Browserify
到底做了什么?安装一下browser-unpack
,就清楚了。
$ npm install browser-unpack -g
然后,将前面生成的compile.js解包。
$ browser-unpack <pre class="brush:php;toolbar:false">[ { "id":1, "source":"module.exports = function(x) {\n console.log(x);\n};", "deps":{} }, { "id":2, "source":"var foo = require(\"./foo\");\nfoo(\"Hi\");", "deps":{"./foo":1}, "entry":true }]
可以看到,browerify
将所有模块放入一个数组,id
属性是模块的编号,source
属性是模块的源码,deps
属性是模块的依赖。
因为 main.js
里面加载了 foo.js
,所以 deps
属性就指定 ./foo
对应1号模块。执行的时候,浏览器遇到 require('./foo')
语句,就自动执行1号模块的 source
属性,并将执行后的 module.exports
属性值输出。
五、ES6
有关es6
模块特性,强烈推荐阮一峰老师的:ECMAScript 6 入门 - Module 的语法专栏。
要说 ES6
模块特性,那么就先说说 ES6
模块跟 CommonJS
模块的不同之处。
ES6
模块输出的是值的引用,输出接口动态绑定,而CommonJS
输出的是值的拷贝;ES6
模块编译时执行,而CommonJS
模块总是在运行时加载。
CommonJS
模块输出的是值的拷贝(原始值的拷贝),也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
// a.jsvar b = require('./b');console.log(b.foo);setTimeout(() => { console.log(b.foo); console.log(require('./b').foo);}, 1000);// b.jslet foo = 1;setTimeout(() => { foo = 2;}, 500);module.exports = { foo: foo,};// 执行:node a.js// 执行结果:// 1// 1// 1
上面代码说明,b 模块加载以后,它的内部 foo 变化就影响不到输出的 exports.foo 了。这是因为 foo 是一个原始类型的值,会被缓存。所以如果你想要在 CommonJS
中动态获取模块中的值,那么就需要借助于函数延时执行的特性。
// a.jsvar b = require('./b');console.log(b.foo);setTimeout(() => { console.log(b.foo); console.log(require('./b').foo);}, 1000);// b.jsmodule.exports.foo = 1; // 同 exports.foo = 1 setTimeout(() => { module.exports.foo = 2;}, 500);// 执行:node a.js// 执行结果:// 1// 2// 2
所以我们可以总结一下:
CommonJS
模块重复引入的模块并不会重复执行,再次获取模块直接获得暴露的module.exports
对象。- 如果你需要处处获取到模块内的最新值的话,也可以每次更新数据的时候每次都要去更新
module.exports
上的值- 如果暴露的
module.exports
的属性是个对象,那就不存在这个问题了。
相关推荐:javascript视频教程
以上是JavaScript模組化程式設計規範之CommonJS、AMD、CMD、ES6的詳細內容。更多資訊請關注PHP中文網其他相關文章!

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

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

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

WebStorm Mac版
好用的JavaScript開發工具

Dreamweaver CS6
視覺化網頁開發工具