Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产亚洲精品福利在线,激情免费视频,国产亚洲精品线观看77

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          10年總結:JavaScript性能優化的小知識總結

          10年總結:JavaScript性能優化的小知識總結,你知道幾個?

          于想讓自己有一個提升,進不了一個更加廣闊的天地,總得找一個屬于自己的居所好好生存,所以平時會有意無意的去積累一些使用 jQuerry 的常用知識,特別是對于性能要求這一塊,總是會想是不是有更好的方式來實現。下面是我總結的一些小技巧,僅供參考。

          前言

          一直在學習 javascript,也有看過《犀利開發 Jquery 內核詳解與實踐》,對這本書的評價只有兩個字犀利,可能是對 javascript 理解的還不夠透徹異或是自己太笨,更多的是自己不擅于思考懶得思考以至于里面說的一些精髓都沒有太深入的理解。

          鑒于想讓自己有一個提升,進不了一個更加廣闊的天地,總得找一個屬于自己的居所好好生存,所以平時會有意無意的去積累一些使用 jQuerry 的常用知識,特別是對于性能要求這一塊,總是會想是不是有更好的方式來實現。

          下面是我總結的一些小技巧,僅供參考。(我先會說一個總標題,然后用一小段話來說明這個意思 再最后用一個 demo 來簡單言明)

          避免全局查找

          在一個函數中會用到全局對象存儲為局部變量來減少全局查找,因為訪問局部變量的速度要比訪問全局變量的速度更快些

          function search() {

          //當我要使用當前頁面地址和主機域名

          alert(window.location.href + window.location.host);

          }

          //最好的方式是如下這樣 先用一個簡單變量保存起來

          function search() {

          var location=window.location;

          alert(location.href + location.host);

          }

          定時器

          如果針對的是不斷運行的代碼,不應該使用 setTimeout,而應該是用 setInterval,因為 setTimeout 每一次都會初始化一個定時器,而 setInterval 只會在開始的時候初始化一個定時器

          var timeoutTimes=0;

          function timeout() {

          timeoutTimes++;

          if (timeoutTimes < 10) {

          setTimeout(timeout, 10);

          }

          }

          timeout();

          //可以替換為:

          var intervalTimes=0;

          function interval() {

          intervalTimes++;

          if (intervalTimes >=10) {

          clearInterval(interv);

          }

          }

          var interv=setInterval(interval, 10);

          字符串連接

          如果要連接多個字符串,應該少使用 +=,如

          s+=a;

          s+=b;

          s+=c;

          1

          2

          3

          應該寫成 s+=a + b + c;

          而如果是收集字符串,比如多次對同一個字符串進行 +=操作的話,最好使用一個緩存,使用 JavaScript 數組來收集,最后使用 join 方法連接起來

          var buf=[];

          for (var i=0; i < 100; i++) {

          buf.push(i.toString());

          }

          var all=buf.join("");

          避免 with 語句

          和函數類似 ,with 語句會創建自己的作用域,因此會增加其中執行的代碼的作用域鏈的長度,由于額外的作用域鏈的查找,在 with 語句中執行的代碼肯定會比外面執行的代碼要慢,在能不使用 with 語句的時候盡量不要使用 with 語句。

          with (a.b.c.d) {

          property1=1;

          property2=2;

          }

          //可以替換為:

          var obj=a.b.c.d;

          obj.property1=1;

          obj.property2=2;

          數字轉換成字符串

          般最好用 “” + 1 來將數字轉換成字符串,雖然看起來比較丑一點,但事實上這個效率是最高的,性能上來說:

          ("" +) > String() > .toString() > new String()

          1

          浮點數轉換成整型

          很多人喜歡使用 parseInt(),其實 parseInt() 是用于將字符串轉換成數字,而不是浮點數和整型之間的轉換,我們應該使用 Math.floor() 或者 Math.round()

          各種類型轉換

          var myVar="3.14159",

          str="" + myVar, // to string

          i_int=~ ~myVar, // to integer

          f_float=1 * myVar, // to float

          b_bool=!!myVar, /* to boolean - any string with length

          and any number except 0 are true */

          array=[myVar]; // to array

          如果定義了 toString() 方法來進行類型轉換的話,推薦顯式調用 toString(),因為內部的操作在嘗試所有可能性之后,會嘗試對象的 toString() 方法嘗試能否轉化為 String,所以直接調用這個方法效率會更高

          多個類型聲明

          在 JavaScript 中所有變量都可以使用單個 var 語句來聲明,這樣就是組合在一起的語句,以減少整個腳本的執行時間,就如上面代碼一樣,上面代碼格式也挺規范,讓人一看就明了。

          插入迭代器

          var name=values[i]; i++;

          1

          前面兩條語句可以寫成

          var name=values[i++]

          1

          使用直接量

          var aTest=new Array(); //替換為

          var aTest=[];

          var aTest=new Object; //替換為

          var aTest={};

          var reg=new RegExp(); //替換為

          var reg=/../;

          //如果要創建具有一些特性的一般對象,也可以使用字面量,如下:

          var oFruit=new O;

          oFruit.color="red";

          oFruit.name="apple";

          //前面的代碼可用對象字面量來改寫成這樣:

          var oFruit={ color: "red", name: "apple" };

          一旦需要更新 DOM, 請考慮使用文檔碎片來構建 DOM 結構,然后再將其添加到現存的文檔中。

          for (var i=0; i < 1000; i++) {

          var el=document.createElement('p');

          el.innerHTML=i;

          document.body.appendChild(el);

          }

          //可以替換為:

          var frag=document.createDocumentFragment();

          for (var i=0; i < 1000; i++) {

          var el=document.createElement('p');

          el.innerHTML=i;

          frag.appendChild(el);

          }

          document.body.appendChild(frag);

          使用一次 innerHTML 賦值代替構建 dom 元素

          對于大的 DOM 更改,使用 innerHTML 要比使用標準的 DOM 方法創建同樣的 DOM 結構快得多。

          var frag=document.createDocumentFragment();

          for (var i=0; i < 1000; i++) {

          var el=document.createElement('p');

          el.innerHTML=i;

          frag.appendChild(el);

          }

          document.body.appendChild(frag);

          //可以替換為:

          var html=[];

          for (var i=0; i < 1000; i++) {

          html.push('<p>' + i + '</p>');

          }

          document.body.innerHTML=html.join('');

          通過模板元素 clone,替代 createElement

          很多人喜歡在 JavaScript 中使用 document.write 來給頁面生成內容。事實上這樣的效率較低,如果需要直接插入 HTML,可以找一個容器元素,比如指定一個 div 或者 span,并設置他們的 innerHTML 來將自己的 HTML 代碼插入到頁面中。通常我們可能會使用字符串直接寫 HTML 來創建節點,其實這樣做,1 無法保證代碼的有效性 2 字符串操作效率低,所以應該是用 document.createElement() 方法,而如果文檔中存在現成的樣板節點,應該是用 cloneNode() 方法,因為使用 createElement() 方法之后,你需要設置多次元素的屬性,使用 cloneNode() 則可以減少屬性的設置次數——同樣如果需要創建很多元素,應該先準備一個樣板節點

          var frag=document.createDocumentFragment();

          for (var i=0; i < 1000; i++) {

          var el=document.createElement('p');

          el.innerHTML=i;

          frag.appendChild(el);

          }

          document.body.appendChild(frag);

          //替換為:

          var frag=document.createDocumentFragment();

          var pEl=document.getElementsByTagName('p')[0];

          for (var i=0; i < 1000; i++) {

          var el=pEl.cloneNode(false);

          el.innerHTML=i;

          frag.appendChild(el);

          }

          document.body.appendChild(frag);

          使用 firstChild 和 nextSibling 代替 childNodes 遍歷 dom 元素

          var nodes=element.childNodes;

          for (var i=0, l=nodes.length; i < l; i++) {

          var node=nodes[i];

          //……

          }

          //可以替換為:

          var node=element.firstChild;

          while (node) {

          //……

          node=node.nextSibling;

          刪除 DOM 節點

          刪除 dom 節點之前, 一定要刪除注冊在該節點上的事件, 不管是用 observe 方式還是用 attachEvent 方式注冊的事件, 否則將會產生無法回收的內存。另外,在 removeChild 和 innerHTML=’’二者之間, 盡量選擇后者. 因為在 sIEve(內存泄露監測工具) 中監測的結果是用 removeChild 無法有效地釋放 dom 節點

          使用事件代理

          任何可以冒泡的事件都不僅僅可以在事件目標上進行處理,目標的任何祖先節點上也能處理,使用這個知識就可以將事件處理程序附加到更高的地方負責多個目標的事件處理,同樣,對于內容動態增加并且子節點都需要相同的事件處理函數的情況,可以把事件注冊提到父節點上,這樣就不需要為每個子節點注冊事件監聽了。另外,現有的 js 庫都采用 observe 方式來創建事件監聽, 其實現上隔離了 dom 對象和事件處理函數之間的循環引用, 所以應該盡量采用這種方式來創建事件監聽

          重復使用的調用結果,事先保存到局部變量

          //避免多次取值的調用開銷

          var h1=element1.clientHeight + num1;

          var h4=element1.clientHeight + num2;

          //可以替換為:

          var eleHeight=element1.clientHeight;

          var h1=eleHeight + num1;

          var h4=eleHeight + num2;

          注意 NodeList

          最小化訪問 NodeList 的次數可以極大的改進腳本的性能

          var images=document.getElementsByTagName('img');

          for (var i=0, len=images.length; i < len; i++) {

          }

          編寫 JavaScript 的時候一定要知道何時返回 NodeList 對象,這樣可以最小化對它們的訪問

          • 進行了對 getElementsByTagName() 的調用
          • 獲取了元素的 childNodes 屬性
          • 獲取了元素的 attributes 屬性
          • 訪問了特殊的集合,如 document.forms、document.images 等等

          要了解了當使用 NodeList 對象時,合理使用會極大的提升代碼執行速度

          優化循環

          可以使用下面幾種方式來優化循環

          • 減值迭代

          大多數循環使用一個從 0 開始、增加到某個特定值的迭代器,在很多情況下,從最大值開始,在循環中不斷減值的迭代器更加高效

          • 簡化終止條件

          由于每次循環過程都會計算終止條件,所以必須保證它盡可能快,也就是說避免屬性查找或者其它的操作,最好是將循環控制量保存到局部變量中,也就是說對數組或列表對象的遍歷時,提前將 length 保存到局部變量中,避免在循環的每一步重復取值。

          var list=document.getElementsByTagName('p');

          for (var i=0; i < list.length; i++) {

          //……

          }

          //替換為:

          var list=document.getElementsByTagName('p');

          for (var i=0, l=list.length; i < l; i++) {

          //……

          }

          • 簡化循環體

          循環體是執行最多的,所以要確保其被最大限度的優化

          • 使用后測試循環

          在 JavaScript 中,我們可以使用 for(;,while(),for(in) 三種循環,事實上,這三種循環中 for(in) 的效率極差,因為他需要查詢散列鍵,只要可以,就應該盡量少用。for(; 和 while 循環,while 循環的效率要優于 for(;,可能是因為 for(; 結構的問題,需要經常跳轉回去。

          var arr=[1, 2, 3, 4, 5, 6, 7];

          var sum=0;

          for (var i=0, l=arr.length; i < l; i++) {

          sum +=arr[i];

          }

          //可以考慮替換為:

          var arr=[1, 2, 3, 4, 5, 6, 7];

          var sum=0, l=arr.length;

          while (l--) {

          sum +=arr[l];

          }

          最常用的 for 循環和 while 循環都是前測試循環,而如 do-while 這種后測試循環,可以避免最初終止條件的計算,因此運行更快。

          展開循環

          當循環次數是確定的,消除循環并使用多次函數調用往往會更快。

          避免雙重解釋

          如果要提高代碼性能,盡可能避免出現需要按照 JavaScript 解釋的字符串,也就是

          盡量少使用 eval 函數

          使用 eval 相當于在運行時再次調用解釋引擎對內容進行運行,需要消耗大量時間,而且使用 Eval 帶來的安全性問題也是不容忽視的。

          不要使用 Function 構造器

          不要給 setTimeout 或者 setInterval 傳遞字符串參數

          var num=0;

          setTimeout('num++', 10);

          //可以替換為:

          var num=0;

          function addNum() {

          num++;

          }

          setTimeout(addNum, 10);

          縮短否定檢測

          if (oTest !='#ff0000') {

          //do something

          }

          if (oTest !=null) {

          //do something

          }

          if (oTest !=false) {

          //do something

          }

          //雖然這些都正確,但用邏輯非操作符來操作也有同樣的效果:

          if (!oTest) {

          //do something

          }

          條件分支

          將條件分支,按可能性順序從高到低排列:可以減少解釋器對條件的探測次數

          在同一條件子的多(>2)條件分支時,使用 switch 優于 if:switch 分支選擇的效率高于 if,在 IE 下尤為明顯。4 分支的測試,IE 下 switch 的執行時間約為 if 的一半。

          使用三目運算符替代條件分支

          if (a > b) {

          num=a;

          } else {

          num=b;

          }

          //可以替換為:

          num=a > b ? a : b;

          使用常量

          • 重復值: 任何在多處用到的值都應該抽取為一個常量
          • 用戶界面字符串: 任何用于顯示給用戶的字符串,都應該抽取出來以方便國際化
          • URLs: 在 Web 應用中,資源位置很容易變更,所以推薦用一個公共地方存放所有的 URL
          • 任意可能會更改的值: 每當你用到字面量值的時候,你都要問一下自己這個值在未來是不是會變化,如果答案是“是”,那么這個值就應該被提取出來作為一個常量。

          避免與 null 進行比較

          由于 JavaScript 是弱類型的,所以它不會做任何的自動類型檢查,所以如果看到與 null 進行比較的代碼,嘗試使用以下技術替換

          • 如果值應為一個引用類型,使用 instanceof 操作符檢查其構造函數
          • 如果值應為一個基本類型,作用 typeof 檢查其類型
          • 如果是希望對象包含某個特定的方法名,則使用 typeof 操作符確保指定名字的方法存在于對象上

          避免全局量

          全局變量應該全部字母大寫,各單詞之間用_下劃線來連接。盡可能避免全局變量和函數, 盡量減少全局變量的使用,因為在一個頁面中包含的所有 JavaScript 都在同一個域中運行。所以如果你的代碼中聲明了全局變量或者全局函數的話,后面的代碼中載入的腳本文件中的同名變量和函數會覆蓋掉(overwrite)你的。

          //糟糕的全局變量和全局函數

          var current=null;

          function init(){

          //...

          }

          function change() {

          //...

          }

          function verify() {

          //...

          }

          //解決辦法有很多,Christian Heilmann建議的方法是:

          //如果變量和函數不需要在“外面”引用,那么就可以使用一個沒有名字的方法將他們全都包起來。

          (function(){

          var current=null;

          function init() {

          //...

          }

          function change() {

          //...

          }

          function verify() {

          //...

          }

          })();

          //如果變量和函數需要在“外面”引用,需要把你的變量和函數放在一個“命名空間”中

          //我們這里用一個function做命名空間而不是一個var,因為在前者中聲明function更簡單,而且能保護隱私數據

          myNameSpace=function() {

          var current=null;

          function init() {

          //...

          }

          function change() {

          //...

          }

          function verify() {

          //...

          }

          //所有需要在命名空間外調用的函數和屬性都要寫在return里面

          return {

          init: init,

          //甚至你可以為函數和屬性命名一個別名

          set: change

          };

          };

          尊重對象的所有權

          因為 JavaScript 可以在任何時候修改任意對象,這樣就可以以不可預計的方式覆寫默認的行為,所以如果你不負責維護某個對象,它的對象或者它的方法,那么你就不要對它進行修改,具體一點就是說:

          • 不要為實例或原型添加屬性
          • 不要為實例或者原型添加方法
          • 不要重定義已經存在的方法
          • 不要重復定義其它團隊成員已經實現的方法,永遠不要修改不是由你所有的對象,你可以通過以下方式為對象創建新的功能:
          • 創建包含所需功能的新對象,并用它與相關對象進行交互
          • 創建自定義類型,繼承需要進行修改的類型,然后可以為自定義類型添加額外功能

          循環引用

          如果循環引用中包含 DOM 對象或者 ActiveX 對象,那么就會發生內存泄露。內存泄露的后果是在瀏覽器關閉前,即使是刷新頁面,這部分內存不會被瀏覽器釋放。

          簡單的循環引用:

          var el=document.getElementById('MyElement');

          var func=function () {

          //…

          }

          el.func=func;

          func.element=el;

          但是通常不會出現這種情況。通常循環引用發生在為 dom 元素添加閉包作為 expendo 的時候。

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          }

          init();

          init 在執行的時候,當前上下文我們叫做 context。這個時候,context 引用了 el,el 引用了 function,function 引用了 context。這時候形成了一個循環引用。

          下面 2 種方法可以解決循環引用:

          1.置空 dom 對象

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          }

          init();

          //可以替換為:

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          el=null;

          }

          init();

          將 el 置空,context 中不包含對 dom 對象的引用,從而打斷循環應用。

          如果我們需要將 dom 對象返回,可以用如下方法:

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          return el;

          }

          init();

          //可以替換為:

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          try {

          return el;

          } finally {

          el=null;

          }

          }

          init();

          2. 構造新的 context

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          }

          init();

          //可以替換為:

          function elClickHandler() {

          //……

          }

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=elClickHandler;

          }

          init();

          把 function 抽到新的 context 中,這樣,function 的 context 就不包含對 el 的引用,從而打斷循環引用。

          通過 javascript 創建的 dom 對象,必須 append 到頁面中

          IE 下,腳本創建的 dom 對象,如果沒有 append 到頁面中,刷新頁面,這部分內存是不會回收的!

          function create() {

          var gc=document.getElementById('GC');

          for (var i=0; i < 5000; i++) {

          var el=document.createElement('div');

          el.innerHTML="test";

          //下面這句可以注釋掉,看看瀏覽器在任務管理器中,點擊按鈕然后刷新后的內存變化

          gc.appendChild(el);

          }

          }

          釋放 dom 元素占用的內存

          將 dom 元素的 innerHTML 設置為空字符串,可以釋放其子元素占用的內存。

          在 rich 應用中,用戶也許會在一個頁面上停留很長時間,可以使用該方法釋放積累得越來越多的 dom 元素使用的內存。

          釋放 javascript 對象

          在 rich 應用中,隨著實例化對象數量的增加,內存消耗會越來越大。所以應當及時釋放對對象的引用,讓 GC 能夠回收這些內存控件。

          對象: obj=null

          對象屬性: delete obj.myproperty

          數組 item:使用數組的 splice 方法釋放數組中不用的 item

          避免 string 的隱式裝箱

          對 string 的方法調用,比如’xxx’.length,瀏覽器會進行一個隱式的裝箱操作,將字符串先轉換成一個 String 對象。推薦對聲明有可能使用 String 實例方法的字符串時,采用如下寫法:

          var myString=new String('Hello World');

          松散耦合

          1、解耦 HTML/JavaScript

          JavaScript 和 HTML 的緊密耦合:直接寫在 HTML 中的 JavaScript、使用包含內聯代碼的

          HTML 和 JavaScript 的緊密耦合:JavaScript 中包含 HTML,然后使用 innerHTML 來插入一段 html 文本到頁面

          其實應該是保持層次的分離,這樣可以很容易的確定錯誤的來源,所以我們應確保 HTML 呈現應該盡可能與 JavaScript 保持分離

          2、解耦 CSS/JavaScript

          顯示問題的唯一來源應該是 CSS,行為問題的唯一來源應該是 JavaScript,層次之間保持松散耦合才可以讓你的應用程序更加易于維護,所以像以下的代碼 element.style.color=“red” 盡量改為 element.className=“edit”,而且不要在 css 中通過表達式嵌入 JavaScript

          3、解耦應用程序 / 事件處理程序

          將應用邏輯和事件處理程序相分離:一個事件處理程序應該從事件對象中提取,并將這些信息傳送給處理應用邏輯的某個方法中。這樣做的好處首先可以讓你更容易更改觸發特定過程的事件,其次可以在不附加事件的情況下測試代碼,使其更易創建單元測試

          性能方面的注意事項

          1、盡量使用原生方法

          2、switch 語句相對 if 較快

          通過將 case 語句按照最可能到最不可能的順序進行組織

          3、位運算較快

          當進行數字運算時,位運算操作要比任何布爾運算或者算數運算快

          4、巧用 ||和 && 布爾運算符

          function eventHandler(e) {

          if (!e) e=window.event;

          }

          //可以替換為:

          function eventHandler(e) {

          e=e || window.event;

          }

          if (myobj) {

          doSomething(myobj);

          }

          //可以替換為:

          myobj && doSomething(myobj);

          避免錯誤應注意的地方

          1、每條語句末尾須加分號

          在 if 語句中,即使條件表達式只有一條語句也要用 {} 把它括起來,以免后續如果添加了語句之后造成邏輯錯誤

          2、使用 + 號時需謹慎

          JavaScript 和其他編程語言不同的是,在 JavaScript 中,’+‘除了表示數字值相加,字符串相連接以外,還可以作一元運算符用,把字符串轉換為數字。因而如果使用不當,則可能與自增符’++'混淆而引起計算錯誤

          var valueA=20;

          var valueB="10";

          alert(valueA + valueB); //ouput: 2010

          alert(valueA + (+valueB)); //output: 30

          alert(valueA + +valueB); //output:30

          alert(valueA ++ valueB); //Compile error

          3、使用 return 語句需要注意

          一條有返回值的 return 語句不要用 () 括號來括住返回值,如果返回表達式,則表達式應與 return 關鍵字在同一行,以避免壓縮時,壓縮工具自動加分號而造成返回與開發人員不一致的結果

          function F1() {

          var valueA=1;

          var valueB=2;

          return valueA + valueB;

          }

          function F2() {

          var valueA=1;

          var valueB=2;

          return

          valueA + valueB;

          }

          alert(F1()); //output: 3

          alert(F2()); //ouput: undefined

          ==和===的區別

          避免在 if 和 while 語句的條件部分進行賦值,如 if (a=b),應該寫成 if (a==b),但是在比較是否相等的情況下,最好使用全等運行符,也就是使用===和!==操作符會相對于==和!=會好點。==和!=操作符會進行類型強制轉換

          var valueA="1";

          var valueB=1;

          if (valueA==valueB) {

          alert("Equal");

          }

          else {

          alert("Not equal");

          }

          //output: "Equal"

          if (valueA===valueB) {

          alert("Equal");

          }

          else {

          alert("Not equal");

          }

          //output: "Not equal"

          不要使用生偏語法

          不要使用生偏語法,寫讓人迷惑的代碼,雖然計算機能夠正確識別并運行,但是晦澀難懂的代碼不方便以后維護

          函數返回統一類型

          雖然 JavaScript 是弱類型的,對于函數來說,前面返回整數型數據,后面返回布爾值在編譯和運行都可以正常通過,但為了規范和以后維護時容易理解,應保證函數應返回統一的數據類型

          總是檢查數據類型

          要檢查你的方法輸入的所有數據,一方面是為了安全性,另一方面也是為了可用性。用戶隨時隨地都會輸入錯誤的數據。這不是因為他們蠢,而是因為他們很忙,并且思考的方式跟你不同。用 typeof 方法來檢測你的 function 接受的輸入是否合法

          何時用單引號,何時用雙引號

          雖然在 JavaScript 當中,雙引號和單引號都可以表示字符串, 為了避免混亂,我們建議在 HTML 中使用雙引號,在 JavaScript 中使用單引號,但為了兼容各個瀏覽器,也為了解析時不會出錯,定義 JSON 對象時,最好使用雙引號

          部署

          用 JSLint 運行 JavaScript 驗證器來確保沒有語法錯誤或者是代碼沒有潛在的問

          部署之前推薦使用壓縮工具將 JS 文件壓縮

          文件編碼統一用 UTF-8

          JavaScript 程序應該盡量放在 .js 的文件中,需要調用的時候在 HTML 中以

          <html>
          <head>
          <title>DOM 教程</title>
          </head>
          <body>
          <h1>DOM 第一課</h1>
          <p class="example">Hello world!</p>
          <input name="myInput" type="text" size="20" /><br />
          <h1 id="myHeader">This is a header</h1>
          </body>
          </html>

          上面的 HTML 中:

          <html> 節點沒有父節點;它是根節點

          <head> 和 <body> 的父節點是 <html> 節點

          文本節點 "Hello world!" 的父節點是 <p> 節點

          并且:

          <html> 節點擁有兩個子節點:<head> 和 <body>

          <head> 節點擁有一個子節點:<title> 節點

          <title> 節點也擁有一個子節點:文本節點 "DOM 教程"

          <h1> 和 <p> 節點是同胞節點, 同時也是 <body> 的子節點

          并且:

          <head> 元素是 <html> 元素的首個子節點

          <body> 元素是 <html> 元素的最后一個子節點

          <h1> 元素是 <body> 元素的首個子節點

          <p> 元素是 <body> 元素的最后一個子節點

          訪問節點:

          var oLi=document.getElementsByTagName("li");
          var oLi=document.getElementById("myHeader");
          var oLi=document.getElementsByName("myInput"); //通過name屬性訪問

          querySelector訪問方式: IE8開始支持, IE8以下不支持

          var div=document.querySelector("#myHeader"); //通過id訪問
          var div=document.querySelector("li"); //通過標簽訪問
          document.querySelector(".example"); //通過class屬性訪問

          獲取表單值

          document.getElementById(id).value

          querySelector() 方法返回文檔中匹配指定 CSS 選擇器的一個元素。

          注意: querySelector() 方法僅僅返回匹配指定選擇器的第一個元素。

          如果你需要返回所有的元素, 請使用 querySelectorAll() 方法替代。

          利用父子兄關系查找節點:

          使用childNodes屬性

          對象屬性

          nodeName 返回當前節點名字

          元素節點的 nodeName 是標簽名稱

          屬性節點的 nodeName 是屬性名稱

          文本節點的 nodeName 永遠是 #text

          文檔節點的 nodeName 永遠是 #document


          nodeValue 返回當前節點的值, 僅對文本節點和屬性節點

          對于文本節點, nodeValue 屬性包含文本。

          對于屬性節點, nodeValue 屬性包含屬性值。

          nodeValue 屬性對于文檔節點和元素節點是不可用的。

          注意:nodeValue與tagName的區別對于空白節點的返回值:nodeValue返回null, tagName返回undefined

          對于文本節點的返回值:nodeValue返回文本, tagName返回undefined

          nodeType 檢測節點類型:

          alert(document.nodeType);

          元素節點的nodeType值為1; 標簽名稱

          屬性節點的nodeType值為2; 屬性名稱 屬性節點不能算是其元素節點的子節點

          文本節點的nodeType值為3; #text

          注釋(Comment) 8: #comment

          文檔(Document) 9 #document <HTML>

          文檔類型(DocumentType) 10: <!DOCTYPE HTML PUBLIC"...">

          節點 nodeType nodeName nodeValue

          元素節點 1 大寫的標簽名 null

          屬性節點 2 屬性名 屬性值

          文本節點 3 #text 文本值

          tagName 返回標簽的名稱, 僅對元素節點

          parentNode 返回當前節點的父節點, 如果存在的話

          childNodes 返回當前節點的子節點集合

          firstChild 對標記的子節點集合中第一個節點的引用, 如果存在的話

          lastChild 對標記的子節點集合中最后一個節點的引用, 如果存在的話

          previousSibling 對同屬一個父節點的前一個兄弟節點的引用

          nextSibling 對同屬一個父節點的下一個兄弟節點的引用

          Attributes 返回當前節點(標記)屬性的列表 用于XML文件

          ownerDocument 返回節點所屬的根元素

          一些 DOM 對象方法

          getElementById() 返回帶有指定 ID 的元素。

          getElementsByTagName() 返回包含帶有指定標簽名稱的所有元素的節點列表(集合/節點數組)。

          getElementsByName() 返回包含帶有指定類名的所有元素的節點列表。

          appendChild() 把新的子節點添加到指定節點。

          removeChild() 刪除子節點。

          replaceChild() 替換子節點。

          insertBefore() 在指定的子節點前面插入新的子節點。

          createAttribute() 創建屬性節點。

          createElement() 創建元素節點。

          createTextNode() 創建文本節點。

          getAttribute() 返回指定的屬性值。

          setAttribute() 把指定屬性設置或修改為指定的值。

          刪除、替換、插入子節點必須通過父節點的removeChild()方法來完成的

          createAttribute() 創建屬性節點

          var att=document.createAttribute("class");
          att.value="democlass";
          document.getElementsByTagName("H1")[0].setAttributeNode(att);

          以上代碼可以簡化為

          document.getElementsByTagName("H1")[0].class="democlass";

          createAttribute()結合setAttributeNode()使用

          等同于:

          document.getElementsByTagName("H1")[0].setAttributeNode("class", "democlass");

          DOM獲取所有子節點:

          <html>
          <head>
          <title>childNodes</title>
          <script language="javascript">
          function myDOMInspector(){
          var oUl=document.getElementById("myList"); //獲取<ul>標記
          var DOMString="";
          if(oUl.hasChildNodes()){ //判斷是否有子節點
          var oCh=oUl.childNodes;
          for(var i=0;i<oCh.length;i++) //逐一查找
          DOMString +=oCh[i].nodeName + "\n";
          }
          alert(DOMString);
          }
          </script>
          </head>
          <body onload="myDOMInspector()">
          <ul id="myList">
          <li>糖醋排骨</li>
          <li>圓籠粉蒸肉</li>
          <li>泡菜魚</li>
          <li>板栗燒雞</li>
          <li>麻婆豆腐</li>
          </ul>
          </body>
          </html>

          使用parentNode屬性:

          <html>
          <head>
          <title>parentNode</title>
          <script language="javascript">
          function myDOMInspector(){
          var myItem=document.getElementById("myDearFood");
          alert(myItem.parentNode.tagName); //返回值為ul
          }
          </script>
          </head>
          <body onload="myDOMInspector()">
          <ul>
          <li>糖醋排骨</li>
          <li>圓籠粉蒸肉</li>
          <li>泡菜魚</li>
          <li id="myDearFood">板栗燒雞</li>
          <li>麻婆豆腐</li>
          </ul>
          </body>
          </html>

          DOM的兄弟關系:

          <html>
          <head>
          <title>Siblings</title>
          <script language="javascript">
          function myDOMInspector(){
          var myItem=document.getElementById("myDearFood");
          //訪問兄弟節點
          var nextListItem=myItem.nextSibling;
          var preListItem=myItem.previousSibling;
          alert(nextListItem.tagName +" "+ preListItem.tagName);
          }
          </script>
          </head>
          <body onload="myDOMInspector()">
          <ul>
          <li>糖醋排骨</li>
          <li>圓籠粉蒸肉</li>
          <li>泡菜魚</li>
          <li id="myDearFood">板栗燒雞</li>
          <li>麻婆豆腐</li>
          </ul>
          </body>
          </html>

          編寫自定義函數解決Firefox等瀏覽器包含眾多的空格作為文本節點問題。

          <html>
          <head>
          <title>Siblings</title>
          <script language="javascript">
          function nextSib(node){
          var tempLast=node.parentNode.lastChild;
          //判斷是否是最后一個節點,如果是則返回null
          if(node==tempLast)
          return null;
          var tempObj=node.nextSibling;
          //逐一搜索后面的兄弟節點,直到發現元素節點為止
          while(tempObj.nodeType!=1 && tempObj.nextSibling!=null)
          tempObj=tempObj.nextSibling;
          //三目運算符,如果是元素節點則返回節點本身,否則返回null
          return (tempObj.nodeType==1)?tempObj:null;
          }
          function prevSib(node){
          var tempFirst=node.parentNode.firstChild;
          //判斷是否是第一個節點,如果是則返回null
          if(node==tempFirst)
          return null;
          var tempObj=node.previousSibling;
          //逐一搜索前面的兄弟節點,直到發現元素節點為止
          while(tempObj.nodeType!=1 && tempObj.previousSibling!=null)
          tempObj=tempObj.previousSibling;
          return (tempObj.nodeType==1)?tempObj:null;
          }
          function myDOMInspector(){
          var myItem=document.getElementById("myDearFood");
          //獲取后一個元素兄弟節點
          var nextListItem=nextSib(myItem);
          //獲取前一個元素兄弟節點
          var preListItem=prevSib(myItem);
          alert("后一項:" + ((nextListItem!=null)?nextListItem.firstChild.nodeValue:null) + " 前一項:" + ((preListItem!=null)?preListItem.firstChild.nodeValue:null) );
          }
          </script>
          </head>
          <body onload="myDOMInspector()">
          <ul>
          <li>糖醋排骨</li>
          <li>圓籠粉蒸肉</li>
          <li>泡菜魚</li>
          <li id="myDearFood">板栗燒雞</li>
          <li>麻婆豆腐</li>
          </ul>
          </body>
          </html>

          注意:最新版的IE瀏覽器也包含眾多的空格作為文本節點;

          設置節點屬性:

          getAttribute()方法和setAttibute()方法

          <html>
          <head>
          <title>getAttribute()</title>
          <script language="javascript">
          function myDOMInspector(){
          //獲取圖片
          var myImg=document.getElementsByTagName("img")[0];
          //獲取圖片title屬性
          alert(myImg.getAttribute("title")); //也可以用myImg.title獲取屬性值
          }
          </script>
          </head>
          <body onload="myDOMInspector()">
          <img src="01.jpg" title="情人坡" />
          </body>
          </html>
          <html>
          <head>
          <title>setAttribute()</title>
          <script language="javascript">
          function changePic(){
          //獲取圖片
          var myImg=document.getElementsByTagName("img")[0];
          //設置圖片src和title屬性
          myImg.setAttribute("src","02.jpg"); //可以在屬性節點不存在時,添加節點的屬性值;
          myImg.setAttribute("title","紫荊公寓"); //也可以通過myImg.title="紫荊公寓";
          }
          </script>
          </head>
          <body>
          <img src="01.jpg" title="情人坡" onclick="changePic()" />
          </body>
          </html>

          setAttribute()設置HTML標簽的屬性

          oTable.setAttribute("border", "3"); //為表格邊框設置寬度
          oTable.setAttribute("border", 3);
          oTable.setAttribute("border", "3px"); //經過測試, 此種寫法也正確

          建議: 具體格式參照HTML屬性值的語法格式

          setAttibute()設置行內樣式

          obj.setAttribute("style", "position:absolute;left:200px;top:200px");

          注意:具體格式參考CSS樣式的語法格式

          setAttibute()設置事件屬性

          obj.setAttribute("onclick", "remove_img()"); //remove_img() 編寫自定義函數, 這里不能使用自定義函數

          注意:關于文本節點兼容性

          元素節點

          子節點: childNodes children

          首尾子節點: firstChild firstElementChild

          lastChild lastElementChild

          兄弟節點: nextSibling nextElementSibling

          previousSibling previousElementSibling

          childNodes firstChild lastChild nextSibling previousSibling屬性IE6-IE8版本瀏覽器不會返回空白節點,

          IE9以上版本瀏覽器會返回文本節點, W3C瀏覽器(包括火狐瀏覽器)也會返回文本節點

          children firstElementChild lastElementChild nextElementSibling previousElementSibling 只返回元素節點, 不會返回空白節點

          注意: DOM操作必須保住DOM節點必須存在, 當然也包括使用css樣式display:none隱藏的DOM節點, 否則會導致js語法錯誤;

          于想讓自己有一個提升,進不了一個更加廣闊的天地,總得找一個屬于自己的居所好好生存,所以平時會有意無意的去積累一些使用 jQuerry 的常用知識,特別是對于性能要求這一塊,總是會想是不是有更好的方式來實現。下面是我總結的一些小技巧,僅供參考。

          前言

          一直在學習 javascript,也有看過《犀利開發 Jquery 內核詳解與實踐》,對這本書的評價只有兩個字犀利,可能是對 javascript 理解的還不夠透徹異或是自己太笨,更多的是自己不擅于思考懶得思考以至于里面說的一些精髓都沒有太深入的理解。

          鑒于想讓自己有一個提升,進不了一個更加廣闊的天地,總得找一個屬于自己的居所好好生存,所以平時會有意無意的去積累一些使用 jQuerry 的常用知識,特別是對于性能要求這一塊,總是會想是不是有更好的方式來實現。

          下面是我總結的一些小技巧,僅供參考。(我先會說一個總標題,然后用一小段話來說明這個意思 再最后用一個 demo 來簡單言明)

          避免全局查找

          在一個函數中會用到全局對象存儲為局部變量來減少全局查找,因為訪問局部變量的速度要比訪問全局變量的速度更快些

          function search() {

          //當我要使用當前頁面地址和主機域名

          alert(window.location.href + window.location.host);

          }

          //最好的方式是如下這樣 先用一個簡單變量保存起來

          function search() {

          var location=window.location;

          alert(location.href + location.host);

          }

          定時器

          如果針對的是不斷運行的代碼,不應該使用 setTimeout,而應該是用 setInterval,因為 setTimeout 每一次都會初始化一個定時器,而 setInterval 只會在開始的時候初始化一個定時器

          var timeoutTimes=0;

          function timeout() {

          timeoutTimes++;

          if (timeoutTimes < 10) {

          setTimeout(timeout, 10);

          }

          }

          timeout();

          //可以替換為:

          var intervalTimes=0;

          function interval() {

          intervalTimes++;

          if (intervalTimes >=10) {

          clearInterval(interv);

          }

          }

          var interv=setInterval(interval, 10);

          字符串連接

          如果要連接多個字符串,應該少使用 +=,如

          s+=a;

          s+=b;

          s+=c;

          1

          2

          3

          應該寫成 s+=a + b + c;

          而如果是收集字符串,比如多次對同一個字符串進行 +=操作的話,最好使用一個緩存,使用 JavaScript 數組來收集,最后使用 join 方法連接起來

          var buf=[];

          for (var i=0; i < 100; i++) {

          buf.push(i.toString());

          }

          var all=buf.join("");

          避免 with 語句

          和函數類似 ,with 語句會創建自己的作用域,因此會增加其中執行的代碼的作用域鏈的長度,由于額外的作用域鏈的查找,在 with 語句中執行的代碼肯定會比外面執行的代碼要慢,在能不使用 with 語句的時候盡量不要使用 with 語句。

          with (a.b.c.d) {

          property1=1;

          property2=2;

          }

          //可以替換為:

          var obj=a.b.c.d;

          obj.property1=1;

          obj.property2=2;

          數字轉換成字符串

          般最好用 “” + 1 來將數字轉換成字符串,雖然看起來比較丑一點,但事實上這個效率是最高的,性能上來說:

          ("" +) > String() > .toString() > new String()

          1

          浮點數轉換成整型

          很多人喜歡使用 parseInt(),其實 parseInt() 是用于將字符串轉換成數字,而不是浮點數和整型之間的轉換,我們應該使用 Math.floor() 或者 Math.round()

          各種類型轉換

          var myVar="3.14159",

          str="" + myVar, // to string

          i_int=~ ~myVar, // to integer

          f_float=1 * myVar, // to float

          b_bool=!!myVar, /* to boolean - any string with length

          and any number except 0 are true */

          array=[myVar]; // to array

          如果定義了 toString() 方法來進行類型轉換的話,推薦顯式調用 toString(),因為內部的操作在嘗試所有可能性之后,會嘗試對象的 toString() 方法嘗試能否轉化為 String,所以直接調用這個方法效率會更高

          多個類型聲明

          在 JavaScript 中所有變量都可以使用單個 var 語句來聲明,這樣就是組合在一起的語句,以減少整個腳本的執行時間,就如上面代碼一樣,上面代碼格式也挺規范,讓人一看就明了。

          插入迭代器

          var name=values[i]; i++;

          1

          前面兩條語句可以寫成

          var name=values[i++]

          1

          使用直接量

          var aTest=new Array(); //替換為

          var aTest=[];

          var aTest=new Object; //替換為

          var aTest={};

          var reg=new RegExp(); //替換為

          var reg=/../;

          //如果要創建具有一些特性的一般對象,也可以使用字面量,如下:

          var oFruit=new O;

          oFruit.color="red";

          oFruit.name="apple";

          //前面的代碼可用對象字面量來改寫成這樣:

          var oFruit={ color: "red", name: "apple" };

          一旦需要更新 DOM, 請考慮使用文檔碎片來構建 DOM 結構,然后再將其添加到現存的文檔中。

          for (var i=0; i < 1000; i++) {

          var el=document.createElement('p');

          el.innerHTML=i;

          document.body.appendChild(el);

          }

          //可以替換為:

          var frag=document.createDocumentFragment();

          for (var i=0; i < 1000; i++) {

          var el=document.createElement('p');

          el.innerHTML=i;

          frag.appendChild(el);

          }

          document.body.appendChild(frag);

          使用一次 innerHTML 賦值代替構建 dom 元素

          對于大的 DOM 更改,使用 innerHTML 要比使用標準的 DOM 方法創建同樣的 DOM 結構快得多。

          var frag=document.createDocumentFragment();

          for (var i=0; i < 1000; i++) {

          var el=document.createElement('p');

          el.innerHTML=i;

          frag.appendChild(el);

          }

          document.body.appendChild(frag);

          //可以替換為:

          var html=[];

          for (var i=0; i < 1000; i++) {

          html.push('<p>' + i + '</p>');

          }

          document.body.innerHTML=html.join('');

          通過模板元素 clone,替代 createElement

          很多人喜歡在 JavaScript 中使用 document.write 來給頁面生成內容。事實上這樣的效率較低,如果需要直接插入 HTML,可以找一個容器元素,比如指定一個 div 或者 span,并設置他們的 innerHTML 來將自己的 HTML 代碼插入到頁面中。通常我們可能會使用字符串直接寫 HTML 來創建節點,其實這樣做,1 無法保證代碼的有效性 2 字符串操作效率低,所以應該是用 document.createElement() 方法,而如果文檔中存在現成的樣板節點,應該是用 cloneNode() 方法,因為使用 createElement() 方法之后,你需要設置多次元素的屬性,使用 cloneNode() 則可以減少屬性的設置次數——同樣如果需要創建很多元素,應該先準備一個樣板節點

          var frag=document.createDocumentFragment();

          for (var i=0; i < 1000; i++) {

          var el=document.createElement('p');

          el.innerHTML=i;

          frag.appendChild(el);

          }

          document.body.appendChild(frag);

          //替換為:

          var frag=document.createDocumentFragment();

          var pEl=document.getElementsByTagName('p')[0];

          for (var i=0; i < 1000; i++) {

          var el=pEl.cloneNode(false);

          el.innerHTML=i;

          frag.appendChild(el);

          }

          document.body.appendChild(frag);

          使用 firstChild 和 nextSibling 代替 childNodes 遍歷 dom 元素

          var nodes=element.childNodes;

          for (var i=0, l=nodes.length; i < l; i++) {

          var node=nodes[i];

          //……

          }

          //可以替換為:

          var node=element.firstChild;

          while (node) {

          //……

          node=node.nextSibling;

          刪除 DOM 節點

          刪除 dom 節點之前, 一定要刪除注冊在該節點上的事件, 不管是用 observe 方式還是用 attachEvent 方式注冊的事件, 否則將會產生無法回收的內存。另外,在 removeChild 和 innerHTML=’’二者之間, 盡量選擇后者. 因為在 sIEve(內存泄露監測工具) 中監測的結果是用 removeChild 無法有效地釋放 dom 節點

          使用事件代理

          任何可以冒泡的事件都不僅僅可以在事件目標上進行處理,目標的任何祖先節點上也能處理,使用這個知識就可以將事件處理程序附加到更高的地方負責多個目標的事件處理,同樣,對于內容動態增加并且子節點都需要相同的事件處理函數的情況,可以把事件注冊提到父節點上,這樣就不需要為每個子節點注冊事件監聽了。另外,現有的 js 庫都采用 observe 方式來創建事件監聽, 其實現上隔離了 dom 對象和事件處理函數之間的循環引用, 所以應該盡量采用這種方式來創建事件監聽

          重復使用的調用結果,事先保存到局部變量

          //避免多次取值的調用開銷

          var h1=element1.clientHeight + num1;

          var h4=element1.clientHeight + num2;

          //可以替換為:

          var eleHeight=element1.clientHeight;

          var h1=eleHeight + num1;

          var h4=eleHeight + num2;

          注意 NodeList

          最小化訪問 NodeList 的次數可以極大的改進腳本的性能

          var images=document.getElementsByTagName('img');

          for (var i=0, len=images.length; i < len; i++) {

          }

          編寫 JavaScript 的時候一定要知道何時返回 NodeList 對象,這樣可以最小化對它們的訪問

          • 進行了對 getElementsByTagName() 的調用
          • 獲取了元素的 childNodes 屬性
          • 獲取了元素的 attributes 屬性
          • 訪問了特殊的集合,如 document.forms、document.images 等等

          要了解了當使用 NodeList 對象時,合理使用會極大的提升代碼執行速度

          優化循環

          可以使用下面幾種方式來優化循環

          • 減值迭代

          大多數循環使用一個從 0 開始、增加到某個特定值的迭代器,在很多情況下,從最大值開始,在循環中不斷減值的迭代器更加高效

          • 簡化終止條件

          由于每次循環過程都會計算終止條件,所以必須保證它盡可能快,也就是說避免屬性查找或者其它的操作,最好是將循環控制量保存到局部變量中,也就是說對數組或列表對象的遍歷時,提前將 length 保存到局部變量中,避免在循環的每一步重復取值。

          var list=document.getElementsByTagName('p');

          for (var i=0; i < list.length; i++) {

          //……

          }

          //替換為:

          var list=document.getElementsByTagName('p');

          for (var i=0, l=list.length; i < l; i++) {

          //……

          }

          • 簡化循環體

          循環體是執行最多的,所以要確保其被最大限度的優化

          • 使用后測試循環

          在 JavaScript 中,我們可以使用 for(;,while(),for(in) 三種循環,事實上,這三種循環中 for(in) 的效率極差,因為他需要查詢散列鍵,只要可以,就應該盡量少用。for(; 和 while 循環,while 循環的效率要優于 for(;,可能是因為 for(; 結構的問題,需要經常跳轉回去。

          var arr=[1, 2, 3, 4, 5, 6, 7];

          var sum=0;

          for (var i=0, l=arr.length; i < l; i++) {

          sum +=arr[i];

          }

          //可以考慮替換為:

          var arr=[1, 2, 3, 4, 5, 6, 7];

          var sum=0, l=arr.length;

          while (l--) {

          sum +=arr[l];

          }

          最常用的 for 循環和 while 循環都是前測試循環,而如 do-while 這種后測試循環,可以避免最初終止條件的計算,因此運行更快。

          展開循環

          當循環次數是確定的,消除循環并使用多次函數調用往往會更快。

          避免雙重解釋

          如果要提高代碼性能,盡可能避免出現需要按照 JavaScript 解釋的字符串,也就是

          盡量少使用 eval 函數

          使用 eval 相當于在運行時再次調用解釋引擎對內容進行運行,需要消耗大量時間,而且使用 Eval 帶來的安全性問題也是不容忽視的。

          不要使用 Function 構造器

          不要給 setTimeout 或者 setInterval 傳遞字符串參數

          var num=0;

          setTimeout('num++', 10);

          //可以替換為:

          var num=0;

          function addNum() {

          num++;

          }

          setTimeout(addNum, 10);

          縮短否定檢測

          if (oTest !='#ff0000') {

          //do something

          }

          if (oTest !=null) {

          //do something

          }

          if (oTest !=false) {

          //do something

          }

          //雖然這些都正確,但用邏輯非操作符來操作也有同樣的效果:

          if (!oTest) {

          //do something

          }

          條件分支

          將條件分支,按可能性順序從高到低排列:可以減少解釋器對條件的探測次數

          在同一條件子的多(>2)條件分支時,使用 switch 優于 if:switch 分支選擇的效率高于 if,在 IE 下尤為明顯。4 分支的測試,IE 下 switch 的執行時間約為 if 的一半。

          使用三目運算符替代條件分支

          if (a > b) {

          num=a;

          } else {

          num=b;

          }

          //可以替換為:

          num=a > b ? a : b;

          使用常量

          • 重復值: 任何在多處用到的值都應該抽取為一個常量
          • 用戶界面字符串: 任何用于顯示給用戶的字符串,都應該抽取出來以方便國際化
          • URLs: 在 Web 應用中,資源位置很容易變更,所以推薦用一個公共地方存放所有的 URL
          • 任意可能會更改的值: 每當你用到字面量值的時候,你都要問一下自己這個值在未來是不是會變化,如果答案是“是”,那么這個值就應該被提取出來作為一個常量。

          避免與 null 進行比較

          由于 JavaScript 是弱類型的,所以它不會做任何的自動類型檢查,所以如果看到與 null 進行比較的代碼,嘗試使用以下技術替換

          • 如果值應為一個引用類型,使用 instanceof 操作符檢查其構造函數
          • 如果值應為一個基本類型,作用 typeof 檢查其類型
          • 如果是希望對象包含某個特定的方法名,則使用 typeof 操作符確保指定名字的方法存在于對象上

          避免全局量

          全局變量應該全部字母大寫,各單詞之間用_下劃線來連接。盡可能避免全局變量和函數, 盡量減少全局變量的使用,因為在一個頁面中包含的所有 JavaScript 都在同一個域中運行。所以如果你的代碼中聲明了全局變量或者全局函數的話,后面的代碼中載入的腳本文件中的同名變量和函數會覆蓋掉(overwrite)你的。

          //糟糕的全局變量和全局函數

          var current=null;

          function init(){

          //...

          }

          function change() {

          //...

          }

          function verify() {

          //...

          }

          //解決辦法有很多,Christian Heilmann建議的方法是:

          //如果變量和函數不需要在“外面”引用,那么就可以使用一個沒有名字的方法將他們全都包起來。

          (function(){

          var current=null;

          function init() {

          //...

          }

          function change() {

          //...

          }

          function verify() {

          //...

          }

          })();

          //如果變量和函數需要在“外面”引用,需要把你的變量和函數放在一個“命名空間”中

          //我們這里用一個function做命名空間而不是一個var,因為在前者中聲明function更簡單,而且能保護隱私數據

          myNameSpace=function() {

          var current=null;

          function init() {

          //...

          }

          function change() {

          //...

          }

          function verify() {

          //...

          }

          //所有需要在命名空間外調用的函數和屬性都要寫在return里面

          return {

          init: init,

          //甚至你可以為函數和屬性命名一個別名

          set: change

          };

          };

          尊重對象的所有權

          因為 JavaScript 可以在任何時候修改任意對象,這樣就可以以不可預計的方式覆寫默認的行為,所以如果你不負責維護某個對象,它的對象或者它的方法,那么你就不要對它進行修改,具體一點就是說:

          • 不要為實例或原型添加屬性
          • 不要為實例或者原型添加方法
          • 不要重定義已經存在的方法
          • 不要重復定義其它團隊成員已經實現的方法,永遠不要修改不是由你所有的對象,你可以通過以下方式為對象創建新的功能:
          • 創建包含所需功能的新對象,并用它與相關對象進行交互
          • 創建自定義類型,繼承需要進行修改的類型,然后可以為自定義類型添加額外功能

          循環引用

          如果循環引用中包含 DOM 對象或者 ActiveX 對象,那么就會發生內存泄露。內存泄露的后果是在瀏覽器關閉前,即使是刷新頁面,這部分內存不會被瀏覽器釋放。

          簡單的循環引用:

          var el=document.getElementById('MyElement');

          var func=function () {

          //…

          }

          el.func=func;

          func.element=el;

          但是通常不會出現這種情況。通常循環引用發生在為 dom 元素添加閉包作為 expendo 的時候。

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          }

          init();

          init 在執行的時候,當前上下文我們叫做 context。這個時候,context 引用了 el,el 引用了 function,function 引用了 context。這時候形成了一個循環引用。

          下面 2 種方法可以解決循環引用:

          1.置空 dom 對象

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          }

          init();

          //可以替換為:

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          el=null;

          }

          init();

          將 el 置空,context 中不包含對 dom 對象的引用,從而打斷循環應用。

          如果我們需要將 dom 對象返回,可以用如下方法:

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          return el;

          }

          init();

          //可以替換為:

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          try {

          return el;

          } finally {

          el=null;

          }

          }

          init();

          2. 構造新的 context

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=function () {

          //……

          }

          }

          init();

          //可以替換為:

          function elClickHandler() {

          //……

          }

          function init() {

          var el=document.getElementById('MyElement');

          el.onclick=elClickHandler;

          }

          init();

          把 function 抽到新的 context 中,這樣,function 的 context 就不包含對 el 的引用,從而打斷循環引用。

          通過 javascript 創建的 dom 對象,必須 append 到頁面中

          IE 下,腳本創建的 dom 對象,如果沒有 append 到頁面中,刷新頁面,這部分內存是不會回收的!

          function create() {

          var gc=document.getElementById('GC');

          for (var i=0; i < 5000; i++) {

          var el=document.createElement('div');

          el.innerHTML="test";

          //下面這句可以注釋掉,看看瀏覽器在任務管理器中,點擊按鈕然后刷新后的內存變化

          gc.appendChild(el);

          }

          }

          釋放 dom 元素占用的內存

          將 dom 元素的 innerHTML 設置為空字符串,可以釋放其子元素占用的內存。

          在 rich 應用中,用戶也許會在一個頁面上停留很長時間,可以使用該方法釋放積累得越來越多的 dom 元素使用的內存。

          釋放 javascript 對象

          在 rich 應用中,隨著實例化對象數量的增加,內存消耗會越來越大。所以應當及時釋放對對象的引用,讓 GC 能夠回收這些內存控件。

          對象: obj=null

          對象屬性: delete obj.myproperty

          數組 item:使用數組的 splice 方法釋放數組中不用的 item

          避免 string 的隱式裝箱

          對 string 的方法調用,比如’xxx’.length,瀏覽器會進行一個隱式的裝箱操作,將字符串先轉換成一個 String 對象。推薦對聲明有可能使用 String 實例方法的字符串時,采用如下寫法:

          var myString=new String('Hello World');

          松散耦合

          1、解耦 HTML/JavaScript

          JavaScript 和 HTML 的緊密耦合:直接寫在 HTML 中的 JavaScript、使用包含內聯代碼的

          HTML 和 JavaScript 的緊密耦合:JavaScript 中包含 HTML,然后使用 innerHTML 來插入一段 html 文本到頁面

          其實應該是保持層次的分離,這樣可以很容易的確定錯誤的來源,所以我們應確保 HTML 呈現應該盡可能與 JavaScript 保持分離

          2、解耦 CSS/JavaScript

          顯示問題的唯一來源應該是 CSS,行為問題的唯一來源應該是 JavaScript,層次之間保持松散耦合才可以讓你的應用程序更加易于維護,所以像以下的代碼 element.style.color=“red” 盡量改為 element.className=“edit”,而且不要在 css 中通過表達式嵌入 JavaScript

          3、解耦應用程序 / 事件處理程序

          將應用邏輯和事件處理程序相分離:一個事件處理程序應該從事件對象中提取,并將這些信息傳送給處理應用邏輯的某個方法中。這樣做的好處首先可以讓你更容易更改觸發特定過程的事件,其次可以在不附加事件的情況下測試代碼,使其更易創建單元測試

          性能方面的注意事項

          1、盡量使用原生方法

          2、switch 語句相對 if 較快

          通過將 case 語句按照最可能到最不可能的順序進行組織

          3、位運算較快

          當進行數字運算時,位運算操作要比任何布爾運算或者算數運算快

          4、巧用 ||和 && 布爾運算符

          function eventHandler(e) {

          if (!e) e=window.event;

          }

          //可以替換為:

          function eventHandler(e) {

          e=e || window.event;

          }

          if (myobj) {

          doSomething(myobj);

          }

          //可以替換為:

          myobj && doSomething(myobj);

          避免錯誤應注意的地方

          1、每條語句末尾須加分號

          在 if 語句中,即使條件表達式只有一條語句也要用 {} 把它括起來,以免后續如果添加了語句之后造成邏輯錯誤

          2、使用 + 號時需謹慎

          JavaScript 和其他編程語言不同的是,在 JavaScript 中,’+‘除了表示數字值相加,字符串相連接以外,還可以作一元運算符用,把字符串轉換為數字。因而如果使用不當,則可能與自增符’++'混淆而引起計算錯誤

          var valueA=20;

          var valueB="10";

          alert(valueA + valueB); //ouput: 2010

          alert(valueA + (+valueB)); //output: 30

          alert(valueA + +valueB); //output:30

          alert(valueA ++ valueB); //Compile error

          3、使用 return 語句需要注意

          一條有返回值的 return 語句不要用 () 括號來括住返回值,如果返回表達式,則表達式應與 return 關鍵字在同一行,以避免壓縮時,壓縮工具自動加分號而造成返回與開發人員不一致的結果

          function F1() {

          var valueA=1;

          var valueB=2;

          return valueA + valueB;

          }

          function F2() {

          var valueA=1;

          var valueB=2;

          return

          valueA + valueB;

          }

          alert(F1()); //output: 3

          alert(F2()); //ouput: undefined

          ==和===的區別

          避免在 if 和 while 語句的條件部分進行賦值,如 if (a=b),應該寫成 if (a==b),但是在比較是否相等的情況下,最好使用全等運行符,也就是使用===和!==操作符會相對于==和!=會好點。==和!=操作符會進行類型強制轉換

          var valueA="1";

          var valueB=1;

          if (valueA==valueB) {

          alert("Equal");

          }

          else {

          alert("Not equal");

          }

          //output: "Equal"

          if (valueA===valueB) {

          alert("Equal");

          }

          else {

          alert("Not equal");

          }

          //output: "Not equal"

          不要使用生偏語法

          不要使用生偏語法,寫讓人迷惑的代碼,雖然計算機能夠正確識別并運行,但是晦澀難懂的代碼不方便以后維護

          函數返回統一類型

          雖然 JavaScript 是弱類型的,對于函數來說,前面返回整數型數據,后面返回布爾值在編譯和運行都可以正常通過,但為了規范和以后維護時容易理解,應保證函數應返回統一的數據類型

          總是檢查數據類型

          要檢查你的方法輸入的所有數據,一方面是為了安全性,另一方面也是為了可用性。用戶隨時隨地都會輸入錯誤的數據。這不是因為他們蠢,而是因為他們很忙,并且思考的方式跟你不同。用 typeof 方法來檢測你的 function 接受的輸入是否合法

          何時用單引號,何時用雙引號

          雖然在 JavaScript 當中,雙引號和單引號都可以表示字符串, 為了避免混亂,我們建議在 HTML 中使用雙引號,在 JavaScript 中使用單引號,但為了兼容各個瀏覽器,也為了解析時不會出錯,定義 JSON 對象時,最好使用雙引號

          部署

          用 JSLint 運行 JavaScript 驗證器來確保沒有語法錯誤或者是代碼沒有潛在的問

          部署之前推薦使用壓縮工具將 JS 文件壓縮

          文件編碼統一用 UTF-8

          JavaScript 程序應該盡量放在 .js 的文件中,需要調用的時候在 HTML 中以


          主站蜘蛛池模板: 国产成人无码AV一区二区在线观看 | 精品久久一区二区| 国产亚洲一区二区三区在线不卡 | 日韩精品久久一区二区三区| 一区二区在线免费视频| 色国产精品一区在线观看| 国产精品免费大片一区二区| 精品一区二区三人妻视频| 久久se精品一区精品二区| 亚洲男人的天堂一区二区| 四虎成人精品一区二区免费网站| 91亚洲一区二区在线观看不卡| 精品人妻少妇一区二区| 免费在线视频一区| 无码喷水一区二区浪潮AV| 在线中文字幕一区| 亚洲V无码一区二区三区四区观看| 日本一区二区在线免费观看| 国精产品一区一区三区MBA下载 | 国产一区二区精品久久岳√| 亚洲字幕AV一区二区三区四区| 久久一区二区三区免费播放| 亚洲熟女少妇一区二区| 久久免费视频一区| 综合久久一区二区三区| 奇米精品一区二区三区在| 国产在线精品一区二区夜色 | 国产精品538一区二区在线| 国产Av一区二区精品久久| 色综合视频一区二区三区44| 成人丝袜激情一区二区| 女人18毛片a级毛片一区二区| 日韩精品一区二区三区毛片| 成人毛片无码一区二区| 国产精品伦子一区二区三区| 国产精品久久久久一区二区三区 | 日本不卡免费新一区二区三区| 色婷婷AV一区二区三区浪潮| 亚洲AV综合色一区二区三区| 中文字幕乱码一区二区免费| 无码乱人伦一区二区亚洲一|