編寫高質量代碼:Web前端開發修煉之道(三)


第五章:高質量的Javascript

這章的內容我看的最久,這是跟我js基礎沒打好有着莫大的關系,但是還是耐着性子看完了, 不懂的東西都是百度上搜索,理解后再繼續。下面是記錄下來的筆記。

1)如何避免JS沖突

A:匿名函數

在多人合作一個網站時,每個人都會寫自己的JS代碼,定義變量的時候有可能會引起命名沖突,如何避免這種沖突隱患呢?

一種最簡單有效的辦法是“匿名函數”將腳本包起來,讓變量的作用域控制在匿名函數之內

匿名函數:(function (){})() 前面的括號內是函數體,后面的()表示執行。

如:(function(){

  var name,user="test";      //包含在這個匿名函數中的變量,作用域不再是window,而是局限在函數內部。 因為各自包在不同的匿名函數內,也就不再互相沖突了。

  })();

用匿名函數將腳本包起來,可以有效的控制全局變量,避免沖突隱患。

B:解決匿名函數之間的通信問題

上面的匿名函數確實解決了沖突,但是如果兩個代碼段之間需要訪問彼此的變量,那就被分隔開了,沒法訪問對方作用域中的變量.

一個比較好的解決辦法是"在window的作用域下定義一個全局變量",但是從上面的沖突來看,全局變量是引起沖突的殺手,如果又這樣定義,就違背了我們使用匿名函數的初衷,所以應該嚴格控制全局變量的數量!

為了控制全局變量的數量,用Hash對象作為全局變量。  var GLOBAl={};  //一個對象類型的變量作為全局變量,擴展性好

定義好對象類型變量后,在匿名函數A中定義GLOBAL的屬性:GLOBAL.str1="aaa";   在匿名函數B中可以直接訪問var b = BLOBAl.str1;

這樣又出現了一個問題,當在匿名函數B中它也定義一個屬性BLOBAl.str1="bbb"; 這個時候就會把A塊中的屬性str1給覆蓋掉.如何避免這種沖突呢?不可能每個開發者在使用GLOBAL對象之前,都要查找一下綁定了哪些屬性。

這時,命名空間就出現了,它是一種特殊的前綴,在js中它其實是通過一個{}對象來實現的。我們可以給每個匿名函數聲明不同的命名空間,然后每個匿名函數中GLOBAL對象的屬性不要直接掛在GLOBAl對象上,而是掛在此匿名函數的命名空間下,既:window全局的GLOBAL.命名空間.屬性變量  ,這樣申明屬性名稱的時候,即使同名,空間不一樣也不會引起沖突。如: GLOBAL.A={};// 定義命名空間; GLOBAL.A.str1="aaa";//定義屬性變量

復雜的匿名函數中,你還可以生產二級命名空間,如GLOBAL.A={};//一級命名空間,GLOBAL.A.CAT={};GLOBAL.A.DOG={};//二級命名空間;

生成命名空間是一個很常用的功能,可以將其封裝為一個函數。

var GLOBAL={};

GLOBAL.namespace=function(str){

  var arr=str.split("."),o=GLOBAL;

  for(i=(arr[0]=="GLOBAL")?1:0; i<arr.length; i++){

    o[arr[i]]=o[arr[i]] || {};

    o=o[arr[i]];

  }

}   

調用: GLOBAL.namespace(A.DOG);      GLOBAL.namespace(GLOBAL.B);

總結:解決js沖突-------命名空間+全局變量+匿名函數 很好的結合使用才能更好的解決沖突。

C:注釋

添加必要的代碼注釋,可大大提高可維護性,對團隊合作來說,是很重要的。

注釋添加的信息包括:功能說明;工程師姓名;工程師聯系方式;代碼最后修改時間;

讓JS不產生沖突,需要避免全局變量的泛濫,合理使用命名空間,以及給代碼添加注釋。

 

2)JS代碼程序統一入口---------window.onload和DOMready

JS從功能上分為兩部分:1 框架部分(提供的是對JS代碼的組織作用,包括定義全局變量,命名空間等,和具體的應用無關,該部分被每個頁面都包括的)---base層,common層;

                               2 應用部分(頁面功能邏輯的代碼段,不同頁面有不同的功能,不同頁面應用部分的代碼也不同)---page層;

而應用部分的代碼最好包在一個約定好的入口函數里,(程序統一入口,是針對js應用部分來說的),一般初始化的部分會放在一個統一的函數function init(){}中,然后在頁面完全加載完畢后觸發;

window.onload:需要在頁面完全加載完成時才會觸發,包括圖片,flash等富媒體,

DOMReady:只需要判斷頁面內所有的DOM節點是否已經完成加載,至於節點的內容加載是否完成,他並不關心。

所以DOMReady觸發的速度比window.onload快,它比window.onload更適合用來調用初始化函數。【我一般使用jquery,所以頁面加載完畢會用$(fuction(){...});或$(document).ready(function(){...});】

另外一種模擬Ready的效果是將初始化的js代碼塊 放在body結束標簽的前面js ...</body>,這樣會按照順序來載入。

 

3)CSS放在頁頭,JS放在頁尾

瀏覽器加載網頁,加載到JS時,由於腳本比較多,而html代碼還沒有加載,這是頁面會顯示空白,腳本阻塞了html的加載,等到毫不容易加載完成了,有時候會發現這些網頁元素沒有樣式,所以一個好的習慣是,CSS放在頁頭,JS放在頁尾(先加載css,再加載html,再加載js.) 這樣就能適時的將界面呈現給用戶,減少頁面空白的時間。

 

4)引入編譯的概念---------文件壓縮

JS壓縮通常的做法是去掉空格和換行,去掉注釋,將復雜變量名替換為簡單的變量名;壓縮后的js文件的確變小了,但是壓縮后的文件無法反壓縮恢復成原來的模樣。

壓縮命名規則:原名.js    壓縮后的名為:原名-min.js

 

5)js 如何分層----------(為了使代碼更清晰,減少冗余,提高代碼重用率)

和css分層一樣:base層:最低端,兩個職責:1:不同瀏覽器之間js的差異提供統一接口;2:擴展js語言底層提供的接口,比如tostring... 

            base層是給common層和page層提供接口的。

        common層:提供可復用的組件,和頁面內具體功能無關。common層的功能是給page層用的;

        page層:最頂端,該層主要是完成各個頁面內的功能需求。

A:base層

瑣碎知識點:

1:IE和FF下獲取childNodes會不一樣,因為FF會將包括空白、換行等文本信息業當做childNodes中的一員,而IE會忽略它,只將DOM節點作為childNodes的一員。

2:document.all是IE支持的屬性,FF 不支持,通常也可以用來判斷瀏覽器的種類。

3:nextSibling:獲取某個節點的下一個同級節點。

獲得某個父節點下面的子節點,然而瀏覽器不一樣,為了兼容,會根據瀏覽器做出一些處理,將處理封裝成函數,像這類函數將放到base層。如:getnextnode(node)

4:透明度:IE通過濾鏡實現,FF通過css的opacity屬性實現。node.style.filter='alpha(opacity='3')'; nodel.style.opacity=0.3;

5:event:  IE中event對象是window的屬性,作用於全局作用域,在FF中,event是作為事件的參數存在。

一般 function(e){e=window.event||e;}//這樣e在IE和FF下都指向event對象。

event對象的部分屬性名在IE和FF下也是不同的,比如"觸發事件的對象(標簽)"在IE下通過srcElement屬性訪問,在FF下通過target訪問

var element= e.srcElement ||e.target;

6: 冒泡:兩個重疊的標簽點擊其中一個時,另外一個也會被觸發點擊事件,JS 將這種先觸發子容器監聽事件,再觸發父容器監聽事件的現象稱為冒泡。

    為了業務需要,我們需要阻止事件冒泡,在IE中通過設置event對象的cancelBubble屬性為true實現,在FF下通過調用Event對象的stopPropagation方法實現的。

if(document.all){

   e.cancelBubble=true;//IE

}else{

  e.stopPropagation();//FF

}

7:on、attachEvent和addEventListener

我們在定義事件時,往往on**只能定義一次,如果再次定義,就會覆蓋前面定義好的方法。最常見的為onclick事件。

on***的監聽方式沒有疊加效果,最后定義的on***會將前面的事件覆蓋掉。

attachEvent(IE支持的方法)、addEventListener(FF支持的方法),他們支持監聽處理函數的疊加。

例:btn.attachEvent("onclick",function(){...});     btn.addEventListener("click",function(){...});

總結:以上1-7點中,為了兼容不同瀏覽器而封裝的一些兼容處理函數,像這類函數將放到base層。如:getnextnode(node)

8:擴展Js語言底層的接口

例:trim() isNumber() isString() get() $() extend()等等

base層的JS和頁面里的具體應用邏輯無關,屬於框架級的。

B:common層

common層本身依賴於base層提供的接口,需要先加載base層代碼。它與base層的區別是:common層不是簡單的接口,而是相對龐大的組件。(如:設置和獲取cookie,就可以封裝cookie組件). 它和具體功能相關,如果頁面里不需要相關功能,就沒必要加載,而一個易用性和可擴展性都好的組件,代碼量會偏高,所以一般common層的js要按功能分成一個個單獨的文件,如common_cookie.js,common_drag.js,common_tab.js.

common層的JS和頁面里的具體應用邏輯無關,屬於框架級的。

C:page層

base層和common層都是屬於框架級的,page層是屬於應用級的,它可以調用base層的接口和common層的組件

 

6) js類庫

常見的有prototype. Dojo, Mootools,Extjs,jquery,yui等。這么多我用的比較多的是jquery   ,好像extjs也不錯,以后有空學習學習。

 

轉載請注明出處

原文地址:http://www.cnblogs.com/Joans/archive/2012/09/12/2681550.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM