亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

javascript代碼優化的8點總結

2024-05-06 16:42:11
字體:
來源:轉載
供稿:網友

本文將詳細介紹JS編程風格的幾個要點

松耦合

當修改一個組件而不需要更改其他組件時,就做到了松耦合

1、將JS從CSS中抽離:不要使用CSS表達式

//不好的做法.box{width: expression(document.body.offsetWidth + 'px')}

2、將CSS從JS中抽離:通過JS修改CSS樣式時,使用className或classList,不要逐條修改style樣式

//不好的做法一ele.style.color = 'red';ele.style.left= '10px';//不好的做法二ele.style.cssText ='color:red;left:10px;';
.reveal{color:red;left:10px;}//好的做法一ele.className += 'reveal';//好的做法二ele.classList.add('reveal');

3、將JS從HTML中抽離:從JS文件放入外置文件中

4、將HTML從JS中抽離:不要在innerHTML中拼接DOM結構,而是使用字符串模板,如handlerbars

全局變量

創建全局變量被認為是糟糕的實踐,尤其在團隊開發的大背景下更是問題多多。隨著代碼量的增長,全局變量會導致一些非常重要的可維護性難題,全局變量越多,引入錯誤的概率會變得越高

一般而言,有如下三種解決辦法

1、零全局變量

實現方法是使用一個立即調用函數IIFE并將所有腳本放置其中

(function(){ var doc = win.document;})(window);

這種模式的使用場景有限,只要代碼需要被其他的代碼所依賴,或者需要在運行中被不斷擴展或修改,就不能使用這種方式

2、單全局變量和命名空間

依賴盡可能少的全局變量,即只創建一個全局變量,使用單變量模式,如YUI或jQuery

單全局變量,即所創建的這個唯一全局對象名是獨一無二的,并將所有的功能代碼都掛載到這個全局對象上。因此,每個可能的全局變量,都成為唯一全局變量的屬性,從而不會創建多個全局變量

命名空間是簡單的通過全局對象的單一屬性表示的功能性分組。比如Y.DOM下的所有方法都是和DOM操作相關的,Y.Event下的所有方法都是和事件相關的。常見的約定是每個文件中都通過新的全局對象來聲明自己的命名空間

3、使用模塊

模塊是一種通用的功能片段,它并沒有創建新的全局變量或命名空間。相反,所有的這些代碼都存放于一個表示執行一個任務或發布一個接口的單函數中。可以用一個名稱來表示這個模塊,同樣這個模塊可以依賴其他模塊

事件處理

將事件處理相關的代碼和事件環境耦合在一起,導致可維護性很糟糕

1、隔離應用邏輯

將應用邏輯從所有事件處理程序中抽離出來是一種最佳實踐,將應用邏輯和事件處理的代碼拆分開來

//不好的做法function handleClick(event){ var popup = document.getElementById('popup'); popup.style.left = event.clientX + 'px'; popup.style.top = event.clientY + 'px'; popup.className = 'reveal';}addListener(element,'click',handleClick);//好的做法var MyApplication = { handleClick: function(event){  this.showPopup(event); }, showPopup: function(event){  var popup = document.getElementById('popup');  popup.style.left = event.clientX + 'px';  popup.style.top = event.clientY + 'px';  popup.className = 'reveal'; }};addListener(element,'click',function(event){ MyApplication.handleClick(event);});

2、不要分發事件對象

應用邏輯不應當依賴于event對象來正確完成功能,方法接口應該表明哪些數據是必要的。代碼不清晰就會導致bug。最好的辦法是讓事件處理程序使用event對象來處理事件,然后拿到所有需要的數據傳給應用邏輯

//改進的做法var MyApplication = { handleClick: function(event){  this.showPopup(event.clientX,event.clientY); }, showPopup: function(x,y){  var popup = document.getElementById('popup');  popup.style.left = x + 'px';  popup.style.top = y + 'px';  popup.className = 'reveal'; }};addListener(element,'click',function(event){ MyApplication.handleClick(event);});

當處理事件時,最好讓事件程序成為接觸到event對象的唯一的函數。事件處理程序應當在進入應用邏輯之前針對event對象執行任何必要的操作,包括阻止事件冒泡,都應當直接包含在事件處理程序中

//改進的做法var MyApplication = { handleClick: function(event){  event.preventDefault();  event.stopPropagation();  this.showPopup(event.clientX,event.clientY); }, showPopup: function(x,y){  var popup = document.getElementById('popup');  popup.style.left = x + 'px';  popup.style.top = y + 'px';  popup.className = 'reveal'; }};addListener(element,'click',function(event){ MyApplication.handleClick(event);});

配置數據

代碼無非是定義一些指令的集合讓計算機來執行。我們常常將數據傳入計算機,由指令對數據進行操作,并最終產生一個結果。當不得不修改數據時,可能會帶來一些不必要的風險。應當將關鍵數據從代碼中抽離出來

配置數據是指導在應用中寫死的值,且將來可能會被修改,包括如下內容

1、URL2、需要展現給用戶的字符串3、重復的值4、配置項5、任何可能發生變更的值

下面是未處理配置數據的做法

//不好的做法function validate(value){ if(!value){  alert('Invalid value');  location.href="/errors/invalid.php" rel="external nofollow" ; }}function toggleSelected(element){ if(hasClass(element,'selected')){  removeClass(element,'selected'); }else{  addClass(element,'selected'); }}

下面代碼中將配置數據保存在了config對象中,config對象的每個屬性都保存了一個數據片段,每個屬性名都有前綴,用以表明數據的類型(MSG表示展現給用戶的信息,URL表示網絡地址,CSS表示這是一個className)。當然,也可以將整個config對象放到單獨的文件中,這樣對配置數據的修改可以完全和使用這個數據的代碼隔離開來

//好的做法var config = { MSG_INVALID_VALUE: 'Invalid value', URL_INVALID:'/errors/invalid.php', CSS_SELECTED:'selected'}function validate(value){ if(!value){  alert(config.MSG_INVALID_VALUE);  location.href=config.URL_INVALID; }}function toggleSelected(element){ if(hasClass(element,config.CSS_SELECTED)){  removeClass(element,config.CSS_SELECTED); }else{  addClass(element,config.CSS_SELECTED); }}

選擇器優化

將選擇器選擇到的元素作為對象的靜態屬性集中到一個地方統一管理

initializeElements: function() {  var eles = app.Eles;  for (var name in eles) {    if (eles.hasOwnProperty(name)) {      this[name] = $(eles[name]);    }  }}

下面是一個例子

//好的做法app.Eles = {  widgetDiv: ".left-widget div",  inputResize: '.input-resize',  hr: '.hr',  txt: '.input-group-btn button',  cus: '#paper-type-cus',  hid: '#hidden',  mainCon: '#mainCon',  rulerX: '.ruler-x',  rulerY: '.ruler-y',};

函數優化

【提煉函數】

在javascript開發中,大部分時間都在與函數打交道,所以希望這些函數有著良好的命名,函數體內包含的邏輯清晰明了。如果一個函數過長,不得不加上若干注釋才能讓這個函數顯得易讀一些,那這些函數就很有必要進行重構

如果在函數中有一段代碼可以被獨立出來,那最好把這些代碼放進另外一個獨立的函數中。這是一種很常見的優化工作,這樣做的好處主要有以下幾點

1、避免出現超大函數

2、獨立出來的函數有助于代碼復用

3、獨立出來的函數更容易被覆寫

4、獨立出來的函數如果擁有一個良好的命名,它本身就起到了注釋的作用

比如在一個負責取得用戶信息的函數里面,還需要打印跟用戶信息有關的log,那么打印log的語句就可以被封裝在一個獨立的函數里:

var getUserInfo = function(){  ajax( 'http:// xxx.com/userInfo', function( data ){    console.log( 'userId: ' + data.userId );    console.log( 'userName: ' + data.userName );    console.log( 'nickName: ' + data.nickName );  });};//改成:var getUserInfo = function(){  ajax( 'http:// xxx.com/userInfo', function( data ){    printDetails( data );  });};var printDetails = function( data ){  console.log( 'userId: ' + data.userId );  console.log( 'userName: ' + data.userName );  console.log( 'nickName: ' + data.nickName );};

【盡量減少參數數量】

如果調用一個函數時需要傳入多個參數,那這個函數是讓人望而生畏的,必須搞清楚這些參數代表的含義,必須小心翼翼地把它們按照順序傳入該函數。在實際開發中,向函數傳遞參數不可避免,但應該盡量減少函數接收的參數數量。下面舉個非常簡單的示例。有一個畫圖函數draw,它現在只能繪制正方形,接收了3個參數,分別是圖形的width、heigth以及square:

var draw = function(width,height,square){};

但實際上正方形的面積是可以通過width和height計算出來的,于是我們可以把參數square從draw函數中去掉:

var draw = function( width, height ){  var square = width * height;};

假設以后這個draw函數開始支持繪制圓形,需要把參數width和height換成半徑radius,但圖形的面積square始終不應該由客戶傳入,而是應該在draw函數內部,由傳入的參數加上一定的規則計算得來。此時,可以使用策略模式,讓draw函數成為一個支持繪制多種圖形的函數

【傳遞對象參數代替過長的參數列表】

有時候一個函數有可能接收多個參數,而參數的數量越多,函數就越難理解和使用。使用該函數的人首先得搞明白全部參數的含義,在使用的時候,還要小心翼翼,以免少傳了某個參數或者把兩個參數搞反了位置。如果想在第3個參數和第4個參數之中增加一個新的參數,就會涉及許多代碼的修改,代碼如下:

var setUserInfo = function( id, name, address, sex, mobile, qq ){  console.log( 'id= ' + id );  console.log( 'name= ' +name );  console.log( 'address= ' + address );  console.log( 'sex= ' + sex );  console.log( 'mobile= ' + mobile );  console.log( 'qq= ' + qq );};setUserInfo( 1314, 'xiaohuochai', 'beijing', 'male', '150********', 121631835 );

這時可以把參數都放入一個對象內,然后把該對象傳入setUserInfo函數,setUserInfo函數需要的數據可以自行從該對象里獲取?,F在不用再關心參數的數量和順序,只要保證參數對應的key值不變就可以了:

var setUserInfo = function( obj ){    console.log( 'id= ' + obj.id );    console.log( 'name= ' + obj.name );    console.log( 'address= ' + obj.address );    console.log( 'sex= ' + obj.sex );    console.log( 'mobile= ' + obj.mobile );    console.log( 'qq= ' + obj.qq );  };  setUserInfo({    id: 1314,    name: 'xiaohuochai',    address: 'beijing',    sex: 'male',    mobile: '150********',    qq: 121631835  });

條件優化

【合并條件片段】

如果一個函數體內有一些條件分支語句,而這些條件分支語句內部散布了一些重復的代碼,那么就有必要進行合并去重工作。假如有一個分頁函數paging,該函數接收一個參數currPage,currPage表示即將跳轉的頁碼。在跳轉之前,為防止currPage傳入過小或者過大的數字,要手動對它的值進行修正,詳見如下偽代碼:

var paging = function( currPage ){  if ( currPage <= 0 ){    currPage = 0;    jump( currPage ); // 跳轉  }else if ( currPage >= totalPage ){    currPage = totalPage;    jump( currPage ); // 跳轉  }else{    jump( currPage ); // 跳轉  }};

可以看到,負責跳轉的代碼jump(currPage)在每個條件分支內都出現了,所以完全可以把這句代碼獨立出來:

var paging = function( currPage ){  if ( currPage <= 0 ){    currPage = 0;  }else if ( currPage >= totalPage ){    currPage = totalPage;  }  jump( currPage ); // 把jump 函數獨立出來};

【把條件分支語句提煉成函數】

在程序設計中,復雜的條件分支語句是導致程序難以閱讀和理解的重要原因,而且容易導致一個龐大的函數。假設現在有一個需求是編寫一個計算商品價格的getPrice函數,商品的計算只有一個規則:如果當前正處于夏季,那么全部商品將以8折出售。代碼如下:

var getPrice = function( price ){  var date = new Date();  if ( date.getMonth() >= 6 && date.getMonth() <= 9 ){ // 夏天    return price * 0.8;  }  return price;};

觀察這句代碼:

date.getMonth()>=6&&date.getMonth()<=9

這句代碼要表達的意思很簡單,就是判斷當前是否正處于夏天(7~10月)。盡管這句代碼很短小,但代碼表達的意圖和代碼自身還存在一些距離,閱讀代碼的人必須要多花一些精力才能明白它傳達的意圖。其實可以把這句代碼提煉成一個單獨的函數,既能更準確地表達代碼的意思,函數名本身又能起到注釋的作用。代碼如下:

var isSummer = function(){  var date = new Date();  return date.getMonth() >= 6 && date.getMonth() <= 9;};var getPrice = function( price ){  if ( isSummer() ){ // 夏天    return price * 0.8;  }  return price;};

【提前讓函數退出代替嵌套條件分支】

許多程序員都有這樣一種觀念:“每個函數只能有一個入口和一個出口。”現代編程語言都會限制函數只有一個入口。但關于“函數只有一個出口”,往往會有一些不同的看法。下面這段偽代碼是遵守“函數只有一個出口的”的典型代碼:

var del = function( obj ){  var ret;  if ( !obj.isReadOnly ){ // 不為只讀的才能被刪除    if ( obj.isFolder ){ // 如果是文件夾      ret = deleteFolder( obj );    }else if ( obj.isFile ){ // 如果是文件      ret = deleteFile( obj );    }  }  return ret;};

嵌套的條件分支語句絕對是代碼維護者的噩夢,對于閱讀代碼的人來說,嵌套的if、else語句相比平鋪的if、else,在閱讀和理解上更加困難。嵌套的條件分支往往是由一些深信“每個函數只能有一個出口的”程序員寫出的。但實際上,如果對函數的剩余部分不感興趣,那就應該立即退出。引導閱讀者去看一些沒有用的else片段,只會妨礙他們對程序的理解

于是可以挑選一些條件分支,在進入這些條件分支之后,就立即讓這個函數退出。要做到這一點,有一個常見的技巧,即在面對一個嵌套的if分支時,可以把外層if表達式進行反轉。重構后的del函數如下:

var del = function( obj ){  if ( obj.isReadOnly ){ // 反轉if 表達式    return;  }  if ( obj.isFolder ){    return deleteFolder( obj );  }  if ( obj.isFile ){    return deleteFile( obj );  }};

循環優化

【合理使用循環】

在函數體內,如果有些代碼實際上負責的是一些重復性的工作,那么合理利用循環不僅可以完成同樣的功能,還可以使代碼量更少。下面有一段創建XHR對象的代碼,為了簡化示例,只考慮版本9以下的IE瀏覽器,代碼如下:

var createXHR = function(){  var xhr;  try{    xhr = new ActiveXObject( 'MSXML2.XMLHttp.6.0' );  }catch(e){    try{      xhr = new ActiveXObject( 'MSXML2.XMLHttp.3.0' );    }catch(e){      xhr = new ActiveXObject( 'MSXML2.XMLHttp' );    }  }  return xhr;};var xhr = createXHR();

下面靈活地運用循環,可以得到跟上面代碼一樣的效果:

//下面我們靈活地運用循環,可以得到跟上面代碼一樣的效果:var createXHR = function(){  var versions= [ 'MSXML2.XMLHttp.6.0ddd', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp' ];  for ( var i = 0, version; version = versions[ i++ ]; ){    try{      return new ActiveXObject( version );    }catch(e){    }  }};var xhr = createXHR();

【用return退出多重循環】

假設在函數體內有一個兩重循環語句,需要在內層循環中判斷,當達到某個臨界條件時退出外層的循環。大多數時候會引入一個控制標記變量:

var func = function(){  var flag = false;  for ( var i = 0; i < 10; i++ ){    for ( var j = 0; j < 10; j++ ){      if ( i * j >30 ){        flag = true;        break;      }    }    if ( flag === true ){      break;    }  }};

第二種做法是設置循環標記:

var func = function(){  outerloop:  for ( var i = 0; i < 10; i++ ){    innerloop:    for ( var j = 0; j < 10; j++ ){      if ( i * j >30 ){        break outerloop;      }    }  }};

這兩種做法無疑都讓人頭暈目眩,更簡單的做法是在需要中止循環的時候直接退出整個方法:

var func = function(){  for ( var i = 0; i < 10; i++ ){    for ( var j = 0; j < 10; j++ ){      if ( i * j >30 ){        return;      }    }  }};

當然用return直接退出方法會帶來一個問題,如果在循環之后還有一些將被執行的代碼呢?如果提前退出了整個方法,這些代碼就得不到被執行的機會:

var func = function(){  for ( var i = 0; i < 10; i++ ){    for ( var j = 0; j < 10; j++ ){      if ( i * j >30 ){        return;      }    }  }  console.log( i ); // 這句代碼沒有機會被執行};

為了解決這個問題,可以把循環后面的代碼放到return后面,如果代碼比較多,就應該把它們提煉成一個單獨的函數:

var print = function( i ){  console.log( i );};var func = function(){  for ( var i = 0; i < 10; i++ ){    for ( var j = 0; j < 10; j++ ){      if ( i * j >30 ){        return print( i );      }    }  }};func();

 


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品露脸av在线| 欧美在线性视频| 国产精品黄页免费高清在线观看| 亚洲大胆人体视频| 亚洲人成在线免费观看| 亚洲一区亚洲二区| 久久久久久久久久av| 欧美—级高清免费播放| 午夜精品久久久久久久99热浪潮| 国产成人高清激情视频在线观看| 日韩在线激情视频| 青青青国产精品一区二区| 日韩美女在线播放| 国产精品v片在线观看不卡| 国产亚洲精品久久久| 人体精品一二三区| 7m精品福利视频导航| 中日韩午夜理伦电影免费| 亚洲在线免费看| 国产精品视频久久久| 亚洲精品美女在线观看播放| 亚洲欧美日韩精品| 上原亚衣av一区二区三区| 欧美国产精品日韩| 日韩av网址在线观看| 日韩一区二区三区xxxx| 久久69精品久久久久久久电影好| 国产亚洲欧美日韩精品| 国产专区精品视频| 日本亚洲精品在线观看| 国产精品视频男人的天堂| 色青青草原桃花久久综合| 国产精品亚洲第一区| 日韩精品极品在线观看| 国产精品三级美女白浆呻吟| 日韩欧美aⅴ综合网站发布| 亚洲女同性videos| 亚洲综合av影视| 欧美性视频网站| 日韩美女中文字幕| 久久精品中文字幕免费mv| 日韩av免费在线看| 亚洲xxxx18| 久久精品视频在线| 亚洲精品福利资源站| 色无极影院亚洲| 欧美一级电影在线| 精品成人乱色一区二区| 国产一区二区三区在线观看网站| 日韩精品免费电影| 久久久久久国产免费| 2018中文字幕一区二区三区| 91在线观看免费| 日韩欧美国产中文字幕| 亚洲人成电影在线播放| 69久久夜色精品国产69| 亚洲精品日韩欧美| 亚洲免费福利视频| 91久久精品美女| 亚洲一区二区三区视频| 成人网在线免费看| 国产亚洲欧美日韩美女| 91av免费观看91av精品在线| 久久综合伊人77777蜜臀| 欧美大片在线看免费观看| 欧美色道久久88综合亚洲精品| 国产人妖伪娘一区91| 国产精品高潮呻吟视频| 精品视频在线播放免| 亚洲最大福利视频| 日韩精品一二三四区| 色噜噜国产精品视频一区二区| 国产精品欧美日韩一区二区| 国产成人精品在线播放| 色琪琪综合男人的天堂aⅴ视频| 久久成人综合视频| 国产精品青青在线观看爽香蕉| 国模精品视频一区二区三区| 一本色道久久综合狠狠躁篇的优点| 97在线免费观看| 8090理伦午夜在线电影| 国产综合在线看| 国产精品电影观看| 日韩美女av在线| 亚洲r级在线观看| 欧美日韩国产综合新一区| 亚洲成人aaa| 视频一区视频二区国产精品| 久久精品国产96久久久香蕉| 宅男66日本亚洲欧美视频| 久久男人的天堂| 久久这里有精品| 日韩精品中文字| 91网站在线看| 亚洲综合自拍一区| 不卡av电影在线观看| 亚洲午夜精品视频| 国产综合视频在线观看| 国产精品久久久久久久久久久久久久| 奇米一区二区三区四区久久| 亚洲福利视频二区| 国产一区二区三区视频在线观看| 欧美日韩一区二区三区| 国产精品久久在线观看| 456国产精品| 欧美另类在线观看| 欧美成人黑人xx视频免费观看| 91九色单男在线观看| 97在线视频免费| 午夜精品一区二区三区在线视| 国产精品视频xxx| 97精品欧美一区二区三区| 欧美整片在线观看| 麻豆国产va免费精品高清在线| 亚洲国产精品久久久久久| 亚洲r级在线观看| 久久精品最新地址| 97精品视频在线| 色综合久久中文字幕综合网小说| 超碰91人人草人人干| 久久精品国产成人精品| 久久久中文字幕| 久久九九热免费视频| 国产精品吹潮在线观看| 欧美成人午夜激情| 欧美电影在线播放| 欧美性猛交xxxx富婆弯腰| 亚洲精品国产精品国产自| 亚洲国产第一页| 色噜噜狠狠狠综合曰曰曰| 一区二区三区国产视频| 欧美日本在线视频中文字字幕| 丝袜美腿精品国产二区| 欧美大片免费观看在线观看网站推荐| 欧美在线视频网站| 欧美激情网站在线观看| 欧美精品成人91久久久久久久| 国产欧美精品va在线观看| 久久人人爽人人爽人人片av高请| 精品久久中文字幕| 欧美国产日韩免费| 亚洲国产精品久久久久秋霞不卡| 91在线免费看网站| 亚洲欧洲在线观看| 久久天堂电影网| 国产精品永久免费观看| 一道本无吗dⅴd在线播放一区| 国产精品久久久久91| 一本一本久久a久久精品综合小说| 欧美在线性视频| 日韩高清电影免费观看完整版| 国外成人性视频| 在线观看日韩欧美| 国产精品视频在线观看| 欧美性猛交xxxx富婆| 奇门遁甲1982国语版免费观看高清| 日韩精品视频在线观看网址| 日韩精品视频三区| 国产精品久久久久久久久久免费| 国产精品久久久久久久久久三级| 国产精品一区久久| 国产精品一区二区久久久久| 国产精品va在线播放我和闺蜜| 青青久久aⅴ北条麻妃|