javascript 代碼效率優化-重要

  JS代碼的執行效率每每直接影響了頁面的性能,有的時候,實現一樣的功能,不一樣的JS代碼每每在效率上相差不少,有的時候僅僅是因爲咱們的書寫習慣致使的,固然在高級點的瀏覽器中,它們大多都已經幫咱們優化了,但...javascript

  JS代碼的執行效率每每直接影響了頁面的性能,有的時候,實現一樣的功能,不一樣的JS代碼每每在效率上相差不少,有的時候僅僅是因爲咱們的書寫習慣致使的,固然在高級點的瀏覽器中,它們大多都已經幫咱們優化了,可是在中國,萬惡的IE6仍然大量的存在,咱們不得不去考慮它。對於JS代碼的優化,實際上有不少的狀況,有些影響是比較小的,而有些是比較嚴重的,本文中,我把幾個我認爲影響比較嚴重的狀況列出來,供你們參考。 html

1、字符串的拼接

  字符串的拼接在咱們開發中會常常遇到,因此我把其放在首位,咱們每每習慣的直接用+=的方式來拼接字符串,其實這種拼接的方式效率很是的低,咱們能夠用一種巧妙的方法來實現字符串的拼接,那就是利用數組的join方法。前端

 1 <div class="one" id="one"></div>
 2 <input type="button" value="效率低" onclick="func1()" />
 3 <input type="button" value="效率高" onclick="func2()" />
 4 
 5 <script>
 6     //效率低的
 7     function func1(){
 8         var start = new Date().getTime();
 9         var template = "";
10         for(var i = 0; i < 10000; i++){
11             template += "<input type='button' value='a'>";
12         }
13         var end = new Date().getTime();
14         document.getElementById("one").innerHTML = template;
15         alert("用時:" + (end - start) + "毫秒");
16     }
17 
18     //效率高的
19     function func2(){
20         var start = new Date().getTime();
21         var array = [];
22         for(var i = 0; i < 10000; i++){
23             array[i] = "<input type='button' value='a'>";
24         }
25         var end = new Date().getTime();
26         document.getElementById("one").innerHTML = array.join("");
27         alert("用時:" + (end - start) + "毫秒");
28     }
29 </script>

 

  咱們看看其在不一樣瀏覽器下執行的狀況java

\

  咱們會發現,在IE6下其差異是至關明顯的,其實這種狀況在IE的高版本中體現的也很是明顯,可是在Firefox下卻沒有多大的區別,相反第二種的相對效率還要低點,不過只是差異2ms左右,而Chrome也和Firefox相似。另外在這裏順便說明一下,在咱們給數組添加元素的時候,不少人喜歡用數組的原生的方法push,其實直接用arr[i]或者arr[arr.length]的方式要快一點,大概在10000次循環的狀況IE瀏覽器下會有十幾毫秒的差異。node

 

2、for循環

  for循環是咱們常常會遇到的狀況,咱們先看看下面例子: 程序員

 1 <input type="button" value="效率低" onclick="func1()" />
 2 <input type="button" value="效率高" onclick="func2()" />
 3 <script>
 4     var arr = [];
 5     for(var i = 0; i < 10000; i++){
 6         arr[i] = "<div>" + i + "</div>";
 7     }
 8     document.body.innerHTML += arr.join("");
 9 
10     //效率低的
11     function func1(){
12         var divs = document.getElementsByTagName("div");
13         var start = new Date().getTime();
14         for(var i = 0; i < divs.length; i++){
15             //"效率低"
16         }
17         var end = new Date().getTime();
18         alert("用時:" + (end - start) + "毫秒");
19     }
20 
21     //效率高的
22     function func2(){
23         var divs = document.getElementsByTagName("div");
24         var start = new Date().getTime();
25         for(var i = 0, len = divs.length; i < len; i++){
26             //"效率高"
27         }
28         var end = new Date().getTime();
29         alert("用時:" + (end - start) + "毫秒");
30     }
31 </script>

 

 \

  由上表能夠看出,在IE6.0下,其差異是很是明顯,而在Firefox和Chrome下幾乎沒有差異,之因此在IE6.0下會有這種狀況,主要是由於for循環在執行中,第一種狀況會每次都計算一下長度,而第二種狀況倒是在開始的時候計算長度,並把其保存到一個變量中,因此其執行效率要高點,因此在咱們使用for循環的時候,特別是須要計算長度的狀況,咱們應該開始將其保存到一個變量中。可是並非只要是取長度都會出現如此明顯的差異,若是咱們僅僅是操做一個數組,取得的是一個數組的長度,那麼其實兩種方式的寫法都差很少,咱們看下面的例子:數組

 1 <input type="button" value="效率低" onclick="func1()" />
 2 <input type="button" value="效率高" onclick="func2()" />
 3 <script>
 4     var arr2 = [];
 5     for(var i = 0; i < 10000; i++){
 6         arr2[i] = "<div>" + i + "</div>";
 7     }
 8 
 9     //效率低的
10     function func1(){
11         var start = new Date().getTime();
12         for(var i = 0; i < arr2.length; i++){
13             //"效率低"
14         }
15         var end = new Date().getTime();
16         alert("用時:" + (end - start) + "毫秒");
17     }
18 
19     //效率高的
20     function func2(){
21         var start = new Date().getTime();
22         for(var i = 0, len = arr2.length; i < len; i++){
23             //"效率高"
24         }
25         var end = new Date().getTime();
26         alert("用時:" + (end - start) + "毫秒");
27     }
28 </script>

 

\

  從上表能夠看出,若是僅僅是一個數組的話,咱們看到其實兩種寫法都是差很少的,其實若是咱們把循環再上調到100000次的話,也僅僅是差異幾毫秒而已,因此在數組的狀況下,我認爲都是同樣的。對於for循環的優化,也有人提出不少點,有人認爲用-=1,或者從大到小的方式循環等等,我認爲是徹底沒有必要的,這些優化每每實際狀況下根本沒有表現出來,換句話說只是計算機級別的微小的變化,可是給咱們帶來的倒是代碼的可讀性大大的下降,因此實在是得不償失。瀏覽器

 

3、減小頁面的重繪

  減小頁面重繪雖然本質不是JS自己的優化,可是其每每是由JS引發的,而重繪的狀況每每是嚴重影響頁面性能的,因此徹底有必要拿出來,咱們看下面例子閉包

 1 <div id="demo"></div>
 2 <input type="button" value="效率低" onclick="func1()" />
 3 <input type="button" value="效率高" onclick="func2()" />
 4 
 5 <script>
 6     var str = "<div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div><div>這是一個測試字符串</div>";
 7 
 8     //效率低的
 9     function func1(){
10         var obj = document.getElementById("demo");
11         var start = new Date().getTime();
12         for(var i = 0; i < 100; i++){
13             obj.innerHTML += str + i;
14         }
15         var end = new Date().getTime();
16         alert("用時 " + (end - start) + " 毫秒");
17     }
18 
19     //效率高的
20     function func2(){
21         var obj = document.getElementById("demo");
22         var start = new Date().getTime();
23         var arr = [];
24         for(var i = 0; i < 100; i++){
25             arr[i] = str + i;
26         }
27         obj.innerHTML = arr.join("");
28         var end = new Date().getTime();
29         alert("用時 " + (end - start) + " 毫秒");
30     }
31 </script>

  在例子中,我只是用了100次的循環,由於若是用10000次循環的話,瀏覽器基本上就卡住不動了,可是即便是100次的循環,咱們看看下面的執行結果。app

 

\

  能夠看到的是,這簡直是一個驚人的結果,僅僅100次的循環,無論是在什麼瀏覽器下,都出現瞭如此之大的差異,另外咱們還發現,在這裏,IE6的執行效率竟然比起Firefox還要好不少,可見Firefox在頁面重繪這方面並無作一些的優化。這裏還要注意的是,通常影響頁面重繪的不只僅是innerHTML,若是改變元素的樣式,位置等狀況都會觸發頁面重繪,因此在平時必定要注意這點。

 

4、減小做用域鏈上的查找次數

  咱們知道,js代碼在執行的時候,若是須要訪問一個變量或者一個函數的時候,它須要遍歷當前執行環境的做用域鏈,而遍歷是從這個做用域鏈的前端一級一級的向後遍歷,直到全局執行環境,因此這裏每每會出現一個狀況,那就是若是咱們須要常常訪問全局環境的變量對象的時候,咱們每次都必須在當前做用域鏈上一級一級的遍歷,這顯然是比較耗時的,咱們看下面的例子: 

 1 <div id="demo"></div>
 2 <input id="but1" type="button" onclick="func1()" value="效率低"/>
 3 <input id="but2" type="button" onclick="func2()" value="效率高"/>
 4 
 5 <script>
 6     function func1(){
 7         var start = new Date().getTime();
 8         for(var i = 0; i < 10000; i++){
 9             var but1 = document.getElementById("but1");
10             var but2 = document.getElementById("but2");
11             var inputs = document.getElementsByTagName("input");
12             var divs = document.getElementsByTagName("div");
13             var but1 = document.getElementById("but1");
14             var but2 = document.getElementById("but2");
15             var inputs = document.getElementsByTagName("input");
16             var divs = document.getElementsByTagName("div");
17             var but1 = document.getElementById("but1");
18             var but2 = document.getElementById("but2");
19             var inputs = document.getElementsByTagName("input");
20             var divs = document.getElementsByTagName("div");
21             var but1 = document.getElementById("but1");
22             var but2 = document.getElementById("but2");
23             var inputs = document.getElementsByTagName("input");
24             var divs = document.getElementsByTagName("div");
25             var but1 = document.getElementById("but1");
26             var but2 = document.getElementById("but2");
27             var inputs = document.getElementsByTagName("input");
28             var divs = document.getElementsByTagName("div");
29             var but1 = document.getElementById("but1");
30             var but2 = document.getElementById("but2");
31             var inputs = document.getElementsByTagName("input");
32             var divs = document.getElementsByTagName("div");
33         }
34         var end = new Date().getTime();
35         alert("用時 " + (end - start) + " 毫秒");
36     }
37 
38     function func2(){
39         var start = new Date().getTime();
40         var doc = document;
41         for(var i = 0; i < 10000; i++){
42             var but1 = doc.getElementById("but1");
43             var but2 = doc.getElementById("but2");
44             var inputs = doc.getElementsByTagName("input");
45             var divs = doc.getElementsByTagName("div");
46             var but1 = doc.getElementById("but1");
47             var but2 = doc.getElementById("but2");
48             var inputs = doc.getElementsByTagName("input");
49             var divs = doc.getElementsByTagName("div");
50             var but1 = doc.getElementById("but1");
51             var but2 = doc.getElementById("but2");
52             var inputs = doc.getElementsByTagName("input");
53             var divs = doc.getElementsByTagName("div");
54             var but1 = doc.getElementById("but1");
55             var but2 = doc.getElementById("but2");
56             var inputs = doc.getElementsByTagName("input");
57             var divs = doc.getElementsByTagName("div");
58             var but1 = doc.getElementById("but1");
59             var but2 = doc.getElementById("but2");
60             var inputs = doc.getElementsByTagName("input");
61             var divs = doc.getElementsByTagName("div");
62             var but1 = doc.getElementById("but1");
63             var but2 = doc.getElementById("but2");
64             var inputs = doc.getElementsByTagName("input");
65             var divs = doc.getElementsByTagName("div");
66         }
67         var end = new Date().getTime();
68         alert("用時 " + (end - start) + " 毫秒");
69     }
70 </script>

   上面代碼中,第二種狀況是先把全局對象的變量放到函數裏面先保存下來,而後直接訪問這個變量,而第一種狀況是每次都遍歷做用域鏈,直到全局環境,咱們看到第二種狀況實際上只遍歷了一次,而第一種狀況倒是每次都遍歷了,因此咱們看看其執行結果:

\

  從上表中能夠看出,其在IE6下差異仍是很是明顯的,並且這種差異在多級做用域鏈和多個全局變量的狀況下還會表現的很是明顯。

 

5、避免雙重解釋

  雙重解釋的狀況也是咱們常常會碰到的,有的時候咱們沒怎麼考慮到這種狀況會影響到效率,雙重解釋通常在咱們使用eval、new Function和setTimeout等狀況下會遇到,咱們看看下面的例子:

 1 <div id="demo"></div>
 2 <input id="but1" type="button" onclick="func1()" value="效率低">
 3 <input id="but2" type="button" onclick="func2()" value="效率高">
 4 
 5 <script>
 6     var sum, num1 = 1, num2 = 2;
 7     function func1(){
 8         var start = new Date().getTime();
 9         for(var i = 0; i < 10000; i++){
10             var func = new Function("sum+=num1;num1+=num2;num2++;");
11             func();
12         }
13         var end = new Date().getTime();
14         alert("用時 " + (end - start) + " 毫秒");
15     }
16     
17     function func2(){
18         var start = new Date().getTime();
19         for(var i = 0; i < 10000; i++){
20             sum+=num1;
21             num1+=num2;
22             num2++;
23         }
24         var end = new Date().getTime();
25         alert("用時 " + (end - start) + " 毫秒");
26     }
27 </script>

 

  第一種狀況咱們是使用了new Function來進行雙重解釋,而第二種是避免了雙重解釋,咱們看看在不一樣瀏覽器下的表現:

\

  能夠看到,在全部的瀏覽器中,雙重解釋都是有很大開銷的,因此在實際當中要儘可能避免雙重解釋。

  感謝"SeaSunK"對第四點測試報告錯誤的指正,如今已經修改過來了。至於最後一點提出的func1每次都初始化,沒有可比性,因此我給換了eval,結果發現,在IE6.0下仍是有影響,並且在Firefox下,使用eval對效率的影響程度更加厲害,在Firefox下,若是10000次循環,須要十多秒的時間,因此我把循環都變成了1000次。看代碼和報告

 1 <div id="demo"></div>
 2 <input id="but1" type="button" onclick="func1()" value="效率低">
 3 <input id="but2" type="button" onclick="func2()" value="效率高">
 4 <script>
 5     var sum, num1 = 1, num2 = 2;
 6     function func1(){
 7         var start = new Date().getTime();
 8         for(var i = 0; i < 1000; i++){
 9             eval("sum+=num1;num1+=num2;num2++;");
10         }
11         var end = new Date().getTime();
12         alert("用時 " + (end - start) + " 毫秒");
13     }
14     function func2(){
15         var start = new Date().getTime();
16         for(var i = 0; i < 1000; i++){
17             sum+=num1;
18             num1+=num2;
19             num2++;
20         }
21         var end = new Date().getTime();
22         alert("用時 " + (end - start) + " 毫秒");
23     }
24 </script>

 

\

6、DOM執行效率

1.1 使用DocumentFragment優化屢次append,使用文檔碎片

說明:添加多個dom元素時,先將元素append到DocumentFragment中,最後統一將DocumentFragment添加到頁面。

該作法能夠減小頁面渲染dom元素的次數。經IE和Fx下測試,在append1000個元素時,效率能提升10%-30%,Fx下提高較爲明顯。

 1 <script>
 2     修改前:
 3     for (var i = 0; i < 1000; i++) {
 4         var el = document.createElement('p');
 5         el.innerHTML = i;
 6         document.body.appendChild(el);
 7     }
 8 
 9     修改後:
10     var frag = document.createDocumentFragment();
11     for (var i = 0; i < 1000; i++) {
12         var el = document.createElement('p');
13         el.innerHTML = i;
14         frag.appendChild(el);
15     }
16 
17     document.body.appendChild(frag);
18 </script>

 

1.2 經過模板元素clone,替代createElement

說明:經過一個模板dom對象cloneNode,效率比直接建立element高。

性能提升不明顯,約爲10%左右。在低於100個元素create和append操做時,沒有優點。

 1 <script>
 2     服用前:
 3     var frag = document.createDocumentFragment();
 4     for (var i = 0; i < 1000; i++) {
 5         var el = document.createElement('p');
 6         el.innerHTML = i;
 7         frag.appendChild(el);
 8     }
 9 
10     document.body.appendChild(frag);
11 
12     服用後:
13     var frag = document.createDocumentFragment();
14     var pEl = document.getElementsByTagName('p')[0];
15     for (var i = 0; i < 1000; i++) {
16         var el = pEl.cloneNode(false);
17         el.innerHTML = i;
18         frag.appendChild(el);
19     }
20 
21     document.body.appendChild(frag);
22 </script>

 

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

  說明:根據數據構建列表樣式的時候,使用設置列表容器innerHTML的方式,比構建dom元素並append到頁面中的方式,效率有數量級上的提升。

 1 <script>
 2     服用前:
 3     var frag = document.createDocumentFragment();
 4     for (var i = 0; i < 1000; i++) {
 5         var el = document.createElement('p');
 6         el.innerHTML = i;
 7         frag.appendChild(el);
 8     }
 9 
10     document.body.appendChild(frag);
11 
12     服用後:
13     var html = [];
14     for (var i = 0; i < 1000; i++) {
15         html.push('<p>' + i + '</p>');
16     }
17 
18     document.body.innerHTML = html.join('');
19 </script>

 

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

說明:約能得到30%-50%的性能提升。逆向遍歷時使用lastChild和previousSibling。

 1 <script>
 2     // 服用前:
 3     var nodes = element.childNodes;
 4     for (var i = 0, l = nodes.length; i < l; i++) {
 5         var node = nodes;
 6              ……
 7     }
 8 
 9     // 服用後:
10     var node = element.firstChild;
11     while (node) {
12     ……
13      node = node.nextSibling;
14     }
15 </script>

 

7、字符串執行效率

2.1 使用Array作爲StringBuffer,代替字符串拼接的操做

  說明:IE在對字符串拼接的時候,會建立臨時的String對象;經測試,在IE下,當拼接的字符串愈來愈大時,運行效率會急劇降低。Fx和Opera都對字符串拼接操做進行了優化;經測試,在Fx下,使用Array的join方式執行時間約爲直接字符串拼接的1.4倍。

 1 <script>
 2     // 服用前:
 3     var now = new Date();
 4     var str = '';
 5     for (var i = 0; i < 10000; i++) {
 6         str += '123456789123456789';
 7     }
 8     alert(new Date() - now);
 9 
10     // 服用後:
11     var now = new Date();
12     var strBuffer = [];
13     for (var i = 0; i < 10000; i++) {
14         strBuffer.push('123456789123456789');
15     }
16     var str = strBuffer.join('');
17     alert(new Date() - now);
18 </script>

 

8、循環語句執行效率

3.1 將循環控制量保存到局部變量

  說明:對數組和列表對象的遍歷時,提早將length保存到局部變量中,避免在循環的每一步重複取值。

 1 <script>
 2     // 服用前:
 3     var list = document.getElementsByTagName('p');
 4     for (var i = 0; i < list.length; i++) {
 5     ……
 6     }
 7 
 8     // 服用後:
 9     var list = document.getElementsByTagName('p');
10     for (var i = 0, l = list.length; i < l; i++) {
11     ……
12     }
13 </script>

 

3.2 順序無關的遍歷時,用while替代for

說明:該方法能夠減小局部變量的使用。比起效率優化,更能直接看到的是字符數量的優化。該作法有程序員強迫症的嫌疑。

 1 <script>
 2     // 服用前:
 3     var arr = [1,2,3,4,5,6,7];
 4     var sum = 0;
 5     for (var i = 0, l = arr.length; i &lt; l; i++) {
 6         sum += arr;
 7     }
 8     
 9     // 服用後:
10     var arr = [1,2,3,4,5,6,7];
11     var sum = 0, l = arr.length;
12     while (l--) {
13         sum += arr[l];
14     }
15 </script>

 

9、條件分支執行效率

4.1 將條件分支,按可能性順序從高到低排列

說明:能夠減小解釋器對條件的探測次數。

 

4.2 在同一條件子的多(>2)條件分支時,使用switch優於if

說明:switch分支選擇的效率高於if,在IE下尤其明顯。4分支的測試,IE下switch的執行時間約爲if的一半。

 

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

 1 <script>
 2     // 服用前:
 3     if (a > b) {
 4         num = a;
 5     }
 6     else {
 7         num = b;
 8     }
 9     9
10     // 服用後:
11     num = a > b ? a : b;
12 </script>

 

10、定時器執行效率

5.1 須要不斷執行的時候,優先考慮使用setInterval

  說明:setTimeout每一次都會初始化一個定時器。setInterval只會在開始的時候初始化一個定時器

 1 <script>
 2     //服用前:
 3     var timeoutTimes = 0;
 4     function timeout () {
 5         timeoutTimes++;
 6         if (timeoutTimes < 10) {
 7             setTimeout(timeout, 10);
 8         }
 9     }
10     
11     timeout();
12     
13     //服用後:
14     var intervalTimes = 0;
15     function interval () {
16         intervalTimes++;
17         if (intervalTimes >= 10) {
18             clearInterval(interv);
19         }
20     }
21     
22     var interv = setInterval(interval, 10);
23 </script>

 

5.2 使用function而不是string

說明:若是把字符串做爲setTimeout和setInterval的參數,瀏覽器會先用這個字符串構建一個function。

 1 <script>
 2     // 服用前:
 3     var num = 0;
 4     setTimeout('num++', 10);
 5     
 6     // 服用後:
 7     var num = 0;
 8     function addNum () {
 9         num++;
10     }
11     setTimeout(addNum, 10);
12 </script>

 

11、其餘執行效率

6.1 儘可能不使用動態語法元素

說明:eval、Function、execScript等語句會再次使用javascript解析引擎進行解析,須要消耗大量的執行時間。

 

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

說明:避免屢次取值的調用開銷。

 1 <script>
 2     // 服用前:
 3     var h1 = element1.clientHeight + num1;
 4     var h2 = element1.clientHeight + num2;
 5     
 6     // 服用後:
 7     var eleHeight = element1.clientHeight;
 8     var h1 = eleHeight + num1;
 9     var h2 = eleHeight + num2;
10 </script>

 

6.3 使用直接量

說明:

var a = new Array(param,param,...) -> var a = []

var foo = new Object() -> var foo = {}

var reg = new RegExp() -> var reg = /.../

 

6.4 避免使用with

說明: with雖然能夠縮短代碼量,可是會在運行時構造一個新的scope。

OperaDev上還有這樣的解釋,使用with語句會使得解釋器沒法在語法解析階段對代碼進行優化。對此說法,沒法驗證。

 1 <script>
 2     // 服用前:
 3     with (a.b.c.d) {
 4         property1 = 1;
 5         property2 = 2;
 6     }
 7     
 8     // 服用後:
 9     var obj = a.b.c.d;
10     obj.property1 = 1;
11     obj.property2 = 2;
12 </script>

 

6.5 巧用||和&&布爾運算符

重要程度:★★★

 1 <script>
 2     // 服用前:
 3     function eventHandler (e) {
 4         if(!e) e = window.event;
 5     }
 6     
 7     // 服用後:
 8     function eventHandler (e) {
 9         e = e || window.event;
10     }
11     
12     // 服用前:
13     if (myobj) {
14         doSomething(myobj);
15     }
16     
17     // 服用後:
18     myobj && doSomething(myobj)
19 </script>

 

6.6 類型轉換

說明:

1).    數字轉換成字符串,應用"" + 1,性能上:("" +) > String() > .toString() > new String();

2).    浮點數轉換成整型,不使用parseInt(), parseInt()是用於將字符串轉換成數字,而不是浮點數和整型之間的轉換,建議使用Math.floor()或者Math.round()

3).    對於自定義的對象,推薦顯式調用toString()。內部操做在嘗試全部可能性以後,會嘗試對象的toString()方法嘗試可否轉化爲String。

 

12、內存管理

2.1 循環引用

  說明:若是循環引用中包含DOM對象或者ActiveX對象,那麼就會發生內存泄露。內存泄露的後果是在瀏覽器關閉前,即便是刷新頁面,這部份內存不會被瀏覽器釋放。

 1 <script>
 2     // 簡單的循環引用:   
 3     var el = document.getElementById('MyElement');
 4     var func = function () {…}
 5     el.func = func;
 6     func.element = el;
 7     
 8     // 可是一般不會出現這種狀況。一般循環引用發生在爲dom元素添加閉包做爲expendo的時候。    
 9     // 如:
10     function init() {
11         var el = document.getElementById('MyElement');
12         el.onclick = function () {……}
13     }
14     init();
15 </script>

 

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

 

下面2種方法能夠解決循環引用:

1)    置空dom對象

 1 <script>
 2     // 服用前:
 3     function init() {
 4         var el = document.getElementById('MyElement');
 5         el.onclick = function () {……}
 6     }
 7 
 8     init();
 9 
10     // 服用後:
11     function init() {
12         var el = document.getElementById('MyElement');
13         el.onclick = function () {……}
14         el = null;
15     }
16  
17     init();
18 
19     將el置空,context中不包含對dom對象的引用,從而打斷循環應用。
20     若是咱們須要將dom對象返回,能夠用以下方法:
21     // 服用前:
22     function init() {
23         var el = document.getElementById('MyElement');
24         el.onclick = function () {……}
25         return el;
26     }
27 
28     init();
29 
30     // 服用後:
31     function init() {
32         var el = document.getElementById('MyElement');
33         el.onclick = function () {……}
34         try{
35             return el;
36         }
37         finally {
38             el = null;
39         }
40     }
41 
42     init();
43 </script>

 

2)    構造新的context

 1 <script>
 2     // 服用前:
 3     function init() {
 4         var el = document.getElementById('MyElement');
 5         el.onclick = function () {……}
 6     }
 7     
 8     init();
 9     
10     // 服用後:
11     function elClickHandler() {……}
12     function init() {
13         var el = document.getElementById('MyElement');
14         el.onclick = elClickHandler;
15     }
16     
17     init();
18     
19     把function抽到新的context中,這樣,function的context就不包含對el的引用,從而打斷循環引用。
20 </script>

 

2.2 經過javascript建立的dom對象,必須append到頁面中

說明:IE下,腳本建立的dom對象,若是沒有append到頁面中,刷新頁面,這部份內存是不會回收的!

 1 <script>
 2     // 示例代碼:
 3     function create () {
 4         var gc = document.getElementById('GC');
 5         for (var i = 0; i <5000; i++) {
 6             var el = document.createElement('div');
 7             el.innerHTML = "test";
 8             // 下面這句能夠註釋掉,看看瀏覽器在任務管理器中,點擊按鈕而後刷新後的內存變化
 9             gc.appendChild(el);
10         }
11     }
12 </script>

 

2.3 釋放dom元素佔用的內存

說明:

將dom元素的innerHTML設置爲空字符串,能夠釋放其子元素佔用的內存。

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

 

2.4 釋放javascript對象

說明:在rich應用中,隨着實例化對象數量的增長,內存消耗會愈來愈大。因此應當及時釋放對對象的引用,讓GC可以回收這些內存控件。

對象:obj = null

對象屬性:delete obj.myproperty

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

 

2.5 避免string的隱式裝箱

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

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

相關文章
相關標籤/搜索