本篇文章為大家帶來了關於javascript的相關知識,其中主要介紹了Module模組化程式設計的優點,隨著前端功能越來越複雜,前端程式碼日益膨脹,為了減少維護成本,提高程式碼的可複用性,前端模組化勢在必行,下面一起來看一下,希望對大家有幫助。
【相關推薦:javascript影片教學、web前端】
##背景隨著前端功能越來越複雜,前端程式碼日益膨脹,為了減少維護成本,提高程式碼的可復用性,前端模組化勢在必行。 所有js檔案都在一個html中引入,造成以下不良影響:#請求過多。首先我們要依賴多個模組,那樣就會發送多個請求,導致請求過多
依賴模糊。我們不知道他們的具體依賴關係是什麼,也就是說很容易因為不了解他們之間的依賴關係而導致載入先後順序出錯。
難以維護。以上兩種原因就導致了很難維護,很可能出現牽一發而動全身的情況導致項目出現嚴重的問題。
模組化的概念
模組化是一種處理複雜系統分解成為更好的可管理模組的方式,它可以把系統程式碼分成一系列職責單一,高度解耦且可替換的模組,系統中某一部分的變化將如何影響其它部分就會變得顯而易見,系統的可維護性更加簡單易得。 模組化是一種分治的思想,透過分解複雜系統為獨立的模組實現細粒度的精細控制,對於複雜系統的維護和管理十分有益。模組化也是組件化的基石,是構成現在色彩斑斕的前端世界的前提條件。為什麼需要模組化
前端開發和其他開發工作的主要區別,首先是前端是基於多語言、多層次的編碼和組織工作,其次是前端產品的交付是基於瀏覽器,這些資源是透過增量加載的方式運行到瀏覽器端,如何在開發環境組織好這些碎片化的程式碼和資源,並且保證他們在瀏覽器端快速、優雅的載入和更新,就需要一個模組化系統。 模組化的好處可維護性。因為模組是獨立的,一個設計良好的模組會讓外面的程式碼對自己的依賴越少越好,這樣自己就可以獨立去更新和改進。
命名空間。在 JavaScript 裡面,如果一個變數在最頂層的函數之外聲明,它就直接變成全域可用。因此,常常不小心出現命名衝突的情況。使用模組化開發來封裝變量,可以避免污染全域環境。
重複使用程式碼。我們有時會喜歡從之前寫過的項目中拷貝程式碼到新的項目,這沒有問題,但是更好的方法是,透過模組引用的方式,來避免重複的程式碼庫。我們可以在更新了模組之後,讓引用了這個模組的所有項目都同步更新,還能指定版本號,避免 API 變更帶來的麻煩。
function fn1(){ // ... } function fn2(){ // ... }透過 script 標籤引入文件,呼叫相關的函數。這樣需要手動去管理依賴順序,容易造成命名衝突,污染全局,隨著專案的複雜度增加維護成本也越來越高。 2. 用物件來模擬命名空間
var output = { _count: 0, fn1: function(){ // ... } }這樣可以解決上面的全域污染的問題,有那麼點命名空間的意思,但是隨著專案複雜度增加需要越來越多的這樣的對象需要維護,不說別的,取名字都是個問題。最關鍵的還是內部的屬性還是可以直接存取和修改。 3. 閉包
var module = (function(){ var _count = 0; var fn1 = function (){ // ... } var fn2 = function fn2(){ // ... } return { fn1: fn1, fn2: fn2 } })() module.fn1(); module._count; // undefined
这样就拥有独立的词法作用域,内存中只会存在一份 copy。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域,通过 return 暴露出公共接口供外界调用。这其实就是现代模块化实现的基础。
4. 更多
还有基于闭包实现的松耦合拓展、紧耦合拓展、继承、子模块、跨文件共享私有对象、基于 new 构造的各种方式,这种方式在现在看来都不再优雅。
// 松耦合拓展 // 这种方式使得可以在不同的文件中以相同结构共同实现一个功能块,且不用考虑在引入这些文件时候的顺序问题。 // 缺点是没办法重写你的一些属性或者函数,也不能在初始化的时候就是用module的属性。 var module = (function(my){ // ... return my })(module || {}) // 紧耦合拓展(没有传默认参数) // 加载顺序不再自由,但是可以重载 var module = (function(my){ var old = my.someOldFunc my.someOldFunc = function(){ // 重载方法,依然可通过old调用旧的方法... } return my })(module)
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require、Python 的import,甚至就连 CSS 都有@import,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
目前实现模块化的规范主要有:
CommonJS
CommonJS 是以在浏览器环境之外构建 JavaScript 生态系统为目标而产生的项目,比如在服务器和桌面环境中。
采用同步加载模块的方式,也就是说只有加载完成,才能执行后面的操作。CommonJS 代表:Node 应用中的模块,通俗的说就是你用 npm 安装的模块。
它使用 require 引用和加载模块,exports 定义和导出模块,module 标识模块。使用 require 时需要去读取并执行该文件,然后返回 exports 导出的内容。
CMD
CMD(Common Module Definition)
CMD是SeaJS在推广过程中生产的对模块定义的规范,在Web浏览器端的模块加载器中,SeaJS与RequireJS并称,SeaJS作者为阿里的玉伯。
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。CMD规范整合了CommonJS和AMD规范的特点。在 Sea.js 中,所有 JavaScript 模块都遵循 CMD模块定义规范。
AMD
AMD(Asynchronous Module Definition)
异步模块定义,所谓异步是指模块和模块的依赖可以被异步加载,他们的加载不会影响它后面语句的运行。有效避免了采用同步加载方式中导致的页面假死现象。AMD代表:RequireJS。
AMD一开始是CommonJS规范中的一个草案,全称是Asynchronous Module Definition,即异步模块加载机制。后来由该草案的作者以RequireJS实现了AMD规范,所以一般说AMD也是指RequireJS。
RequireJS是一个工具库,主要用于客户端的模块管理。它的模块管理遵守AMD规范,RequireJS的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。
ES6模块
ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。所以说ES6是编译时加载,不同于CommonJS的运行时加载(实际加载的是一整个对象),ES6模块不是对象,而是通过export命令显式指定输出的代码,输入时也采用静态命令的形式。
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上”use strict”;。
严格模式主要有以下限制。
变量必须声明后再使用
函数的参数不能有同名属性,否则报错
不能使用with语句
不能对只读属性赋值,否则报错
不能使用前缀 0 表示八进制数,否则报错
不能删除不可删除的属性,否则报错
不能删除变量delete prop,会报错,只能删除属性delete global[prop]
eval不会在它的外层作用域引入变量
eval和arguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局对象
不能使用fn.caller和fn.arguments取得函數呼叫的堆疊
增加了保留字(例如protected、static和interface)
上面這些限制,模組都必須遵守。
【相關推薦:javascript影片教學、web前端】
以上是Module模組化程式設計的優點(總結分享)的詳細內容。更多資訊請關注PHP中文網其他相關文章!