從頭開始寫框架(一):淺談JS模塊化發展

博客申請下來已通過去一個月了,一直不知道寫點什麼,畢竟個人文筆不是很好orz。html

不過既然申請下來了,不寫點什麼老是以爲很惋惜。正好最近在本身寫框架,就把本身的進程和一些心得體會分享出來吧。前端

 

寫在前面:編程

這一系列<從頭開始寫框架>文章,算是個人經驗總結。由於之前讀各位大牛的源代碼時,老是會冒出這樣的想法「若是他能把每一步都標註的很明確,那該多好,必定會省下我不少時間。」。可是大牛們願意分享出源代碼已是很感謝了,怎麼還能要求別人這麼多呢~  因此在這系列文章裏,會事無鉅細的把全部細節都標註清楚。方便後來者參閱的時候可以清楚明晰的瞭解每一行代碼的意圖,加深本身的理解。設計模式

 

下面是正文:安全

爲何要先從模塊化的發展談起呢?這是爲了讓新手更容易的理解後面的代碼意圖:爲何有些看起來很簡單的事情要花2倍甚至3倍的時間去完成,以及,多花費的時間對咱們有何幫助? 讓咱們帶着這些問題來展開本篇文章。閉包

 

提及JS模塊化的發展,咱們先從什麼是模塊化開始提及框架

不少前端新人剛入行時,寫的代碼是這樣的:模塊化

 

window.onload=function(){


var a = 1;
var b = 2;

var oBtn=document.getElementById("btn"); oBtn.onclick=function(){   alert(a+b) // 輸出3
} }

 

 

徹底面向過程的寫法與大量的全局變量。函數

這樣寫的好處有什麼?也不能說徹底沒有吧,惟一的好處就是快。想到哪些到哪 ,不用花時間去想代碼結構之類的複雜的事情,用來趕工還挺不錯的對吧?:-Dthis

可是若是說到壞處,就太多了。隨處可見的全局變量致使寫着寫着某一行就忽然報錯了,回去檢查發現是由於某個變量被修改致使報錯。想改已經來不及了,由於太多地方依賴於這個變量,牽一髮而動全身。

同時也會給一塊兒合做的夥伴帶來麻煩,由於不敢隨意修改,因此只能在下面添加新的全局變量來編寫業務,可是由於全局變量氾濫,變量與函數同名的事情時有發生。 

更不用說由於面向過程的編寫方式,致使可重用性幾乎爲零,維護的時候想要改某個小地方時卻發現由於太多的代碼依賴於這個地方而沒法輕易改動等等各類問題。

 

那麼爲了解決這些問題怎麼辦呢?

咱們進化到了函數封裝的階段。

這個階段,咱們的代碼是這樣的:

 
 
function addition(num1,num2){

  return num1+num2;
}
function Subtraction(num1,num2){

  return num1-num2;
}
window.onload=function(){ 
  alert(addition(1,2));//輸出3
  alert(Subtraction(2,2))//輸出0
}

 

恩,好一點了。至少能夠作到複用了。並且減小了不少全局變量。

然而實際工做中,咱們的頁面每每是這樣的:

<!DOCTYPE html>
<html>
<head>
<title>demo</title>
<script src="....js"></script>
<script src="....js"></script>
<script src="....js"></script>
<script src="....js"></script>
<script src="....js"></script>
<script src="....js"></script>
<script src="....js"></script>
<script src="....js"></script>
</head>
<body>

<!--......-->

</body>
</html>

由於方便分工,致使了大量的JS文件引入。而封裝的函數本質上也是全局對象window的方法,因此仍是會發生同名函數的衝突等一系列問題。

 

而對於動輒就是幾千上萬行代碼的大型項目,顯然這樣作仍是不夠安全。

爲了解決這個問題,咱們開始接觸到原型,利用prototype來編寫構造器函數的方式。這也是咱們初次大範圍運用OOP的編程思惟,而咱們也第一次接觸到了設計模式:「構造器模式」

這個時期咱們的代碼是這樣的:

function Calculation(){
    this.a; this.b; } Calculation.prototype.init=function(num1,num2){ this.a=num1; this.b=num2; } Calculation.prototype.add=function(){ return this.a+this.b; } Calculation.prototype.remove=function(){ return this.a-this.b; } var cal = new Calculation(); cal.init(2,2) alert(cal.add())//輸出4 alert(cal.remove())//輸出0

 

恩,看起來已經很好了,解決了大量全局變量的問題,同時複用性也大大提升。

固然,咱們必定不會知足於此。能夠看到,咱們的構造器函數仍然是一個全局函數。仍然有命名衝突的危險。

爲了解決這個問題,咱們開始利用閉包+對象的方式。

閉包是一個好東西,它的主要做用分兩點:1.防止出現大量的全局變量與函數。由於咱們能夠用一個當即執行的匿名函數來模擬全局做用域,同時又不會污染全局做用域。

而對象的值對也能夠有不少種形式:字符串、數字、布爾值、函數! 沒錯,對象的值對能夠用來儲存函數,這樣的話,咱們只須要把代碼寫成這樣:

var Calculator=(function(){

    var a = 2; var b = 2; return { add:function(){ return a+b; }, subtract:function(){ return a-b; }, } })() alert(Calculator.add()) //輸出4 alert(Calculator.subtract()) //輸出0

 

首先這裏的a和b兩個變量由於寫在了匿名函數裏,因此變成了兩個局部變量。這樣作的好處是,外部沒法修改它們。它們是兩個只讀屬性,這樣作就避免了由於修改它們而致使的出錯。

恩,看起來已經很安全了。可是這樣真的就安全了麼?

讓咱們來看看Calculator這個變量,它本質上是一個返回的對象,而對象的鍵值對都是能夠被修改的。這也就致使有可能會有其餘人也同時使用這個名稱定義了一個對象,而誤修改了它的屬性。而這是咱們必定不容許發生的!

並且咱們的工做方式實際上好像並無什麼變化:仍然是每人定義一個全局對象,而後各寫各的,期盼着不要遇到上述問題。這樣帶來的問題仍然是:不利於分工合做。

 

相信到這裏,你已經很是明白,爲何看起來如此簡單的a+b,咱們須要「大費周章」的繞這麼多的彎去解決它,已經這能夠爲咱們帶來怎樣的好處。

 

那麼,讓咱們來想一下,若是咱們能夠把全部的代碼分紅一個個模塊,在咱們須要時,去引用它,不須要時,它也不會對其它部分產生任何影響。

聽起來很美好不是麼?恩,下一章節咱們就來着手實現它。

相關文章
相關標籤/搜索