const MountClickModule = function(){ let num = 0; const handleClick = ()=>{ console.log(++num); } return { countClick:()=>{ document.addEventListener('click',handleClick) } } }(); MountClickModule.countClick(); (function(module) { module.say = ()=>{ console.log(num) //undefined //do something } })(MountClickModule); MountClickModule.say();
這種閉包的壞處:javascript
AMD 和 CommonJS 是兩個互相競爭的標準,都可定義 JavaScript 模塊。除了語法和原理的區別以外,主要區別是 AMD 的設計理念是明確基於瀏覽器,而 CommonJS 的設計是面向通用 JavaScript 環境
AMD 異步模塊定義規範制定了定義模塊的規則,這樣模塊和模塊的依賴能夠被異步加載。這和瀏覽器的異步加載模塊的環境恰好適應(瀏覽器同步加載模塊會致使性能、可用性、調試和跨域訪問等問題)。html
目前,AMD 最流行的實現是 RequireJS
。java
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //Or: return require("beta").verb(); } });
AMD 提供名爲 aplha 的函數,它接收一下參數:git
id
,是個字符串。它指的是定義中模塊的名字,這個參數是可選的。若是沒有提供該參數,模塊的名字應該默認爲模塊加載器請求的指定腳本的名字。能夠看出,AMD 有一下幾項有點:es6
CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出,在 CMD 規範中,一個模塊就是一個文件。代碼的書寫格式以下:github
define(function (require, exports, module) { const foo = require('./foo') a.doSomething() // ... const bar = require('./bar') // 依賴能夠就近書寫 b.doSomething() // do something else })
AMD 的設計明確基於瀏覽器,而 CommonJS 的設計是面向通用 JavaScript 環境。CommonJS 目前在 Nodejs 社區中具備最多的用戶。CommonJS 使用基於文件的模塊,因此每一個文件中都只能定義一個模塊,CommonJs 提供變量 module,該變量具備屬性 exports,經過 exports 很容易擴展屬性。最後,module.exports 做爲模塊的公共接口。typescript
const beta = require('beta'); function alpha(){ return beta.verb(); //Or: return require("beta").verb(); } module.exports = alpha;
CommonJS 要求一個文件就是一個模塊,文件中的代碼就是模塊的一部分,因此不須要使用當即執行函數來包裝變量,在模塊中定義的變量都是安全的再模塊中,不會泄露到全局做用域。只有經過 module.exports
對象暴露的對象或函數才能夠在函數外部訪問
CommonJS 具備如下特色:api
這是 CommonJS 在服務端更流行的緣由。跨域
ES6 模塊結合了CommonJS 和 AMD 的有點,具體以下:數組
既 ES6 結合了兩種模塊化的有點,基於文件系統,既支持異步也支持同步,由於瀏覽器並無實現 ES6 的模塊化 API 因此具體是異步仍是同步取決於loader api
ES6 模塊的主要思想是必須顯示的使用標誌符導出模塊,才能從外部訪問模塊。其餘標誌符,甚至在最頂級做用域中定義的標識符,只能在模塊中使用。
ES6 引入兩個關鍵字:
從index.js模塊中導出:
const hello = 'hello'; export const name = 'yunfly' export function sayHi(){ return `${hello} ${name}!` }
也能夠在模塊最後一塊兒導出:
// foo.js const hello = 'hello'; export const name = 'yunfly' export function sayHi(){ return `${hello} ${name}!` } export { name, sayHi } // export { name as firstName, sayHi } // bar.js // 使用 as 設置導如別名 import { name as firstName, sayHi } from 'foo' console.log(name) sayHi() //bar2.js // 導出所有標識符: import * as sayModule from 'foo'; console.log(sayModule.name) sayModule.sayHi()
// foo.js class Foo {} export default Foo // bar.js import Foo from './foo';
這存在一些可維護性的問題:
文章參考:《JavaScript忍者祕籍》