js便簽筆記(11)——瀏覽TOM大叔博客的學習筆記 part1


1. 前言

這兩天看了一下TOM大叔的《深入理解js系列》中的基礎部分,根據自己的實際情況,做了讀書筆記,記錄了部分容易絆腳的問題。寫篇文章,供大家分享。

 

2. 關於HTMLCollection的“實時查詢”

var divs = document.getElementsByTagName("div"),
      i;
for (i = 0; i < divs.length; i++) {
      //……
}

以上代碼中,會出現性能問題。問題就在於divs是一個HTMLCollection類型的對象,這種類型在每次獲取數據時,都會再重新從dom中分析計算。因此,這里的for循環中,每一步循環都會執行一次divs.length的計算,都會令瀏覽器再重新遍歷一遍dom樹。
所以,應該在循環之外,早早的計算出divs的length屬性值。如下:

var divs = document.getElementsByTagName("div"),
    i,
    length = divs.length;
for (i = 0; i < length; i++) {
    //……
}

3.  for..in...時,注意hasOwnProperty驗證

var obj = {
                a: 10,
                b: 20
            };
            
            // 注意詞句代碼
            Object.prototype.c = 30;

            var item;
            for (item in obj) {
                console.log(item);
            }

以上代碼中,注意中間標注釋的句子。這句代碼加與不加,會對下面的for..in..循環產生影響。加上了就輸出“c”,不加就不輸出“c”。道理很簡單,for..in..循環不光能遍歷obj對象本身就有的屬性,還能遍歷obj原型中的屬性。

要想屏蔽掉原型中的屬性,就用hasOwnProperty函數,如下:

           for (item in obj) {
                if (obj.hasOwnProperty(item)) {
                //if (Object.prototype.hasOwnProperty.call(obj, item)) {
                    console.log(item);
                }
            }

這兩句if判斷語句,都可以用,效果是一樣的。第一個代碼可讀性好,第二個效率相對較高。建議,沒有特殊情況,用第一個即可。

4. 老問題:循環中生成函數/事件的閉包問題

var events = [],
                i = 0;
        //循環創建函數
        for (; i < 10; i++) {
            events[i] = function () {
                console.log(i);
            };
        }

        //驗證結果
        for (i = 0; i < events.length; i++) {
            events[0]();
        }

先看以上代碼,有js開發經驗的人肯定都很熟悉,但是有的人知道,有的人不知道。依照以上代碼,循環遍歷events數組,執行數組元素中的函數,這10個函數都會打印出什么數字?答案是:全都會輸出“10”。下面解釋一下原因:

在每個函數生成/被創建時,系統都會給它分配一個變量的環境,這個環境中也包括閉包的數據。但是,當多個環境,公用一個閉包的數據時,是一種引用的關系,這是重點。引用,不是復制。如果改變了這個公用數據,這些公用的環境獲取時,也是改變后的數據。

所以,在創建第一個函數時,i === 0,第一個函數引用的閉包中i的值就是0;第二個函數被創建時,i === 1,這是,第一個、第二個兩個函數應用閉包中i的值,都是1。以此類推,直到第十個函數創建時,i === 9;但是在for循環的最后一步,又執行了 i++;所以i === 10。

明白了嗎?

想要改變這個問題,想要每個函數都輸出不同的數值,那就需要不讓每個函數都公用一個閉包——讓每個函數使用單獨的閉包數據,不共享。只需講for循環創建函數的部分修改為:

//循環創建函數
        for (; i < 10; i++) {
            events[i] = (function (index) {
                return function (index) {
                    console.log(index);
                }
            })(i);
        }

此時,i作為參數,傳入匿名自動執行函數,賦值給index參數。這個匿名函數的變量環境,就把index保存了下來,而不會隨着i的變化而變化。這就是要點。

 

歡迎關注微博:weibo.com/madai01

 


免責聲明!

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



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