【js】js中的for-in(你讓我情何以堪)

【js】js中的for-in(你讓我情何以堪)

最近在寫一個小demo,碼前端的時候發現一個js中很深的坑:
 因爲前端收到服務器端傳來的數據是一串用“,”隔開的字符串,在處理的時候直接用string.spilt()方法給斷成了一個字符串數組,以便食用;所以在取數組元素的時候想到了用for-in去遍歷。

然鵝!
然鵝!
然鵝!

我還是太年輕了!完全不知道自己已經陷入了一個巨大(zhi zhang)的陷阱!本來完美無缺(bu shi hen lan)的代碼突然變得焦躁起來,大家似乎都對我有不同的意見,爭先恐後的抱起了八阿哥。嗚嗚嗚,不說了,浪費半天時間……
上代碼!

一開始我是這麼搞的

var arr = ["please", "dont", "cast", "my", "type"];

for (var a in arr) {
    document.getElementById(a).value = a;
}

原代碼比較繁瑣,上面是示例代碼,大概就是這麼個操作。
然後就一直報錯啊,提示信息如下:
Uncaught TypeError: Cannot set property ‘value’ of null at :2:38
  到這基本上就知道是因爲dom元素沒有被拿到了,就在循環體裏面的第一行加了句console.log(document.getElementById(a)),打出來是null沒錯,但想來想去還是不明白爲什麼(壓根就沒懷疑for-in這奇葩的語句)。
  折騰了半天沒辦法,只好再前置了一句console.log(a)想着試一試。誒???爲什麼輸出的是些奇怪的東西?

var arr = ["please", "dont", "cast", "my", "type"];

for (var a in arr) {
    console.log(a);
    //document.getElementById(a).value = a;
}
//
 0
 1
 2
 3
 4
 shuffle

這是把arr的索引給遍歷出來了嗎?再查看一下a的類型:

var arr = ["please", "dont", "cast", "my", "type"];

for (var a in arr) {
    console.log(typeof a);
    //document.getElementById(a).value = a;
}
6 string

這什麼鬼?難道for-in是用來遍歷對象的索引的?
驗證一下吧:

//
> var ob = {1:"aa", 2:"bb", 3:"cc"}
< undefined
> ob
< {1: "aa", 2: "bb", 3: "cc"}
  1: "aa"2: "bb"3: "cc"__proto__: Object
> for (var o in ob) {
      console.log(o);
  }
> 1
> 2
> 3
> undefined

//
> var oc = {"a1": "aaa", "a2": "bbb", "a3": "ccc"}
< undefined
> oc
< {a1: "aaa", a2: "bbb", a3: "ccc"}
  a1: "aaa"a2: "bbb"a3: "ccc"__proto__: Object
> for (var o in oc) {
      console.log(o);
  }
> a1
> a2
> a3
< undefined

看來,對於“對象”,for-in語句遍歷出來的是屬性沒錯了。
!!!但是,對於數組,不要用for-in去遍歷它的索引,因爲會出現莫名其妙的東西,比如上面遍歷數組的代碼,最後一個遍歷出的是shuffle,這個是數組原型鏈中的一個屬性,在這裏被莫名其妙的搞出來了。

在js中一般使用的循環有兩種

1.常規的for(var i=0;i<length;i++)

2.for-in:for(var item in list)

但是個人更喜歡使用第一種循環,而不喜歡幾乎從來不使用for-in這種寫法,原因如下:

1.第一種寫法能夠很好的控制循環何時結束,以及對應的索引;而第二種循環無法控制

2.第二種寫法在某種情況下,可能會導致一些奇怪的bug
在這裏插入圖片描述
以上是在jsBin中編輯的代碼,在第一段代碼中,對js的數組Array添加了一個新的方法(prototype 屬性使您有能力向對象添加屬性和方法),爲了在某些時候能夠方便使用。此時,如果用for-in循環出數組arr的內容,會發現在本來想要得到的0,1,2,3的後面會多一個function(){alert(“myfunction”);},這應該不是我們想要得到的結果。

注意:for…in循環會把某個類型的原型(prototype)中方法與屬性給遍歷出來,所以這可能會導致代碼中出現意外的錯誤

上面只是簡單的遍歷一個數組,可能出現的問題還不夠明顯,如下所示
在這裏插入圖片描述

如果我們遍歷的數組中存放的是業務對象,此時會發現,最後一次輸出的是空,在被循環的數組中不存在這個名稱爲空的人員,此時出現的錯誤就導致某些業務無法正常使用或顯示。
對於使用for-in可能導出的bug,有兩種方式避免

1.在循環數組集合時,不使用for-in,統一使用for(var i=0;i<length;i++)這種形式;

2.在for-in循環中增加一個hasOwnProperty的判斷;

hasOwnProperty函數用於指示一個對象自身(不包括原型鏈)是否具有指定名稱的屬性。如果有,返回true,否則返回false
該方法屬於Object對象,由於所有的對象都"繼承"了Object的對象實例,因此幾乎所有的實例對象都可以使用該方法。
在這裏插入圖片描述

上述的兩種方式,個人覺得第一種方式更好,因爲是從根源上避免問題的發生,對於第二種方式,完全是爲了解決問題而增加額外的處理完全沒有這個必要。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章