在練習數組操做的時候,但願實現刪除數組中特定元素(好比刪除字符「1」)的功能
很容易地就想到了利用for循環和splice方法數組
for (let i = 0; i < hobbies.length; i++) { if (hobbies[i] == "1") { hobbies.splice(i, 1); i--; } } 測試結果 "1", "2", "3","1", "1", "4", "1" "2", "3", "4"
如願達成目標,不過想起來還有for in這個東西,彷佛寫起來更簡潔
那用for in行不行呢函數
for(var i in hobbies) { if(hobbies[i]=="1") { hobbies.splice(i,1); i--; } } 測試結果 "1", "2", "3", "1", "1","4" "2", "3", "1", "4"
爲何中間多了一個"1"出來?發生了什麼?測試
添加console.log語句觀測i值的變化code
for(var i in hobbies) { console.log("判斷前"+i); if(hobbies[i]=="1") { hobbies.splice(i,1); i=i+1; } console.log("判斷後"+i) } 結果 判斷前0 判斷後-1 判斷前1 判斷後1 判斷前2 判斷後1 判斷前3 判斷後3
能夠看到,在第一次刪去1後,i--由0變成了-1
但下一次判斷的時候,i直接由-1跳到了1對象
在查詢資料以後,才發現問題出在了i的類型上索引
標準的for循環中的i是number類型,表示的是數組的下標
可是for in循環中的i, 表示的是數組的key是string類型!原型鏈
因爲隱式類型轉換的機制,這個區別被隱藏了起來
由於我測試的時候,用的是i--
而字符串,在運用遞增遞減符號的時候,會把它轉換成number類型
所以雖然i是字符」1「,但也變成了0
若是我用的是i=i+1
字符串加數字,會把數字轉化成字符串拼接,出現01這樣的結果
那麼這個區別就會被我監測到
另外,在splice函數中,參數用了字符串也並無影響最後的結果,由於也進行了隱式轉換字符串
在先前,咱們刪除了元素後,給i--,想固然地以爲下一次變量的值會+1,變回i,就能夠對刪除的元素後面的一個元素進行判斷(由於它的角標數值由i+1,變成了i)
在for循環中是沒事的,但在for in裏面
i--這個操做其實沒有任何意義,即使給i隨便賦一個值,它的下一次取值依然是i+1
由於它是根據數組的元素鍵值(索引)來進行遍歷的,string類型的0,1,2,3,4...arr.length-1已經排好了,並不會由於中途i的值有所變化而改變原型
除此以外,for in還有一些坑回調函數
•做用於數組的for-in循環體除了遍歷數組元素外,還會遍歷自定義屬性。舉個例子,若是你的數組中有一個可枚舉屬性myArray.name,循環將額外執行一次,遍歷到名爲「name」的索引。就連數組原型鏈上的屬性都能被訪問到。
•某些狀況下,for in可能按照隨機順序遍歷數組元素。
所以不適合用for in來遍歷數組
for in適合用來遍歷對象
若是用forEach呢
結果以下
hobbies.forEach(function(value,index,hobbies){ console.log("判斷前"+index); if(value=="1") { hobbies.splice(index,1); console.log(typeof index); index=index-1; // console.log("二"+i); } console.log("判斷後"+index); }); ["1", "2", "3", "1", "1", "4", "1"] 判斷前0 number 判斷後-1 判斷前1 判斷後1 判斷前2 number 判斷後1 判斷前3 判斷後3 判斷前4 number 判斷後3 ["2", "3", "1", "4"]
數組中有幾項,那麼傳遞進去的匿名回調函數就執行幾回