回顧for-in遍曆
在js裡,for-in遍曆的是可迭代對象的key,這點需要特別注意:
"use strcit";var x=['lz','h','is','a sb']; //Array對象是可迭代的for(let i in x){ console.log(i); //用for-in遍曆輸出看一下}
輸出
0123
不方便之處
如果要擷取它的值,就需要再去查詢一次這個key所對應的值:
"use strcit";var x=['lz','h','is','a sb']; //Array對象是可迭代的for(let i in x){ console.log(x[i]); //i是key,而x[i]就是i在x中對應的value}
輸出
lzhisa sb
這種方法顯然有些低效,而且語義上不是那麼直觀,我想要遍曆的只是數組裡的各個元素,為什麼要使用key呢。 嘗試遍曆Set時存在的問題
如果嘗試用這種方式去遍曆Set,前面學了Set可以看成只儲存key的索引值對系,但是卻擷取不到東西:
"use strcit";var x=new Set(['lz','h','is','a sb']); //Set對象是可迭代的for(let i in x){ console.log(i); //如果i視為object的key,嘗試訪問key去遍曆Set}
輸出(沒東西)
我認為這可能體現了Set的無序性,總之沒能遍曆它。 嘗試遍曆Map時存在的問題
Map底層基於樹來實現,它的key大抵也是無序的,沒法遍曆:
"use strcit";var x=new Map([[6,'lz'],[7,'h'],[7.5,'is'],[9.2,'a sb']]); //Map對象是可迭代的for(let i in x){ console.log(i); //如果i視為object的key,嘗試訪問key去遍曆Map的每個鍵}
輸出(沒東西)
for-of遍曆
用於Set
for-of遍曆對於Set遍曆的是集合中的值:
"use strcit";var x=new Set(['lz','h','is','a sb']);for(let i of x){ console.log(i);}
輸出
lzhisa sb
用於Map
for-of遍曆對於Map遍曆的是索引值對的Array形式:
"use strcit";var x=new Map([[6,'lz'],[7,'h'],[7.5,'is'],[9.2,'a sb']]);for(let i of x){ console.log(i);}
輸出
Array [ 6, "lz" ]Array [ 7, "h" ]Array [ 7.5, "is" ]Array [ 9.2, "a sb" ]
用於Array
for-of遍曆對於Arrayt遍曆的是其每個元素的值:
"use strcit";var x=new Array('lz','h','is','a sb');for(let i of x){ console.log(i);}
輸出
lzhisa sb
還有一些差異
在處理Object對象時的差異
for-of是ES6標準下的,在這之前就存在的for-in將Object也視為可迭代對象,遍曆出的是對象的各個屬性和方法的名稱:
"use strcit";//為這個Object對象添加了4個屬性2個方法var ok={ sb1:'lz', sb2:'h', sb3:'is', sb4:'a sb', myfun1:function(x,y){ return x+y; }, myfun2:function(x,y){ return x-y; } };for(let i in ok){ console.log(i);}
輸出
sb1sb2sb3sb4myfun1myfun2
ES6標準不認為Object對象是可迭代的,只認Map,Set,Array,所以不能用for-of遍曆之:
"use strcit";//Object對象var ok={ sb1:'lz', sb2:'h', sb3:'is', sb4:'a sb', myfun1:function(x,y){ return x+y; }, myfun2:function(x,y){ return x-y; } };for(let i of ok){ console.log(i); //嘗試用for-of遍曆之}
輸出(報錯)
TypeError: ok is not iterable
為可迭代對象新增成員時的差異
從for-in的角度來看,Map和Set遍曆不了,Object本來就是由各個成員變數和成員方法組成的,而for-in又認為Object可迭代,新增成員能遍曆是理所當然的。
所以新增成員時的差異只要去看Array對象。
為Array對象新增成員時,for-in會把這個成員和其它下標同一地視為key去遍曆到:
"use strcit";var ok=["lzh","is","rubbish","sb","big sb dog"];ok.name="SBLZH"; //為這個Array對象添加一個成員變數//為這個Array對象添加一個成員方法ok.myfun=function(x,y){ return x+y;};//嘗試用for-in遍曆之for(let i in ok){ console.log(ok[i]);}
輸出
lzhisrubbishsbbig sb dogSBLZHfunction ok.myfun()
現在,如果只有for-in,被添加了成員的Array對象變得很難用了。
而for-of會正確的區分成員和其內容:
"use strcit";var ok=["lzh","is","rubbish","sb","big sb dog"];ok.name="SBLZH"; //為這個Array對象添加一個成員變數//為這個Array對象添加一個成員方法ok.myfun=function(x,y){ return x+y;};//嘗試用for-of遍曆之for(let i of ok){ console.log(i); //注意這裡不需要ok[i]了,只要用一個i}
輸出
lzhisrubbishsbbig sb dog
可迭代對象的forEach()方法
forEach方法接收一個函數為參數,這樣傳進來的函數稱為callback回呼函數。
在每次迭代的過程中都會為這個函數傳入一些參數來調用它一次,當然形參的名字是任意合法的都一樣。用這個forEach()方法就可以把遍曆+做事情寫的非常簡潔了。
對於Object對象,ES6已經明確指出它不是可迭代對象,Object對象自然沒有forEach()方法。 屬於Array對象的forEach()方法
"use strcit";var ok=["lzh","is","rubbish","sb","big sb dog"];var control=false; //用於控制只在第一次輸出對象自己ok.forEach( //傳進來三個參數依次是(目前的元素值,目前的下標,本數組) function(now_element,now_index,thisArray){ //第三個參數每次迭代都一樣的,只輸出一次看一下就好 if(control===false){ control=true; console.log("這個Array是"+thisArray); console.log("第3個參數的類型是"+typeof thisArray); } console.log("ok["+now_index+"]="+now_element); });
輸出
這個Array是lzh,is,rubbish,sb,big sb dog第3個參數的類型是objectok[0]=lzhok[1]=isok[2]=rubbishok[3]=sbok[4]=big sb dog
屬於Set對象的forEach()方法
注意在Set對象上使用時傳進來的前兩個參數是完全一樣的。
"use strcit";var ok=new Set(["lzh","is","rubbish","sb","big sb dog"]);var control=false; //用於控制只在第一次輸出對象自己ok.forEach( //傳進來三個參數依次是(目前的元素值,目前的元素值,本集合) //畢竟Set作為集合不涉及下標(無序),傳進來的前兩個參數都是元素值 function(now_element,now_elem,thisSet){ //第三個參數每次迭代都一樣的,只輸出一次看一下就好 if(control===false){ control=true; console.log("這個Set是"+thisSet); console.log("第3個參數的類型是"+typeof thisSet); } console.log("第1個參數="+now_element); console.log("第2個參數="+now_elem); });
輸出
這個Set是[object Set]第3個參數的類型是object第1個參數=lzh第2個參數=lzh第1個參數=is第2個參數=is第1個參數=rubbish第2個參數=rubbish第1個參數=sb第2個參數=sb第1個參數=big sb dog第2個參數=big sb dog
屬於Map對象的forEach()方法
"use strcit";var ok=new Map([[7,"lzh"],[8.5,"is"],['666阿',"rubbish"],[-30,"sb"],[250,"big sb dog"]]);var control=false; //用於控制只在第一次輸出對象自己ok.forEach( //傳進來三個參數依次是(目前的value,目前的key,本Map) function(now_value,now_key,thisMap){ //第三個參數每次迭代都一樣的,只輸出一次看一下就好 if(control===false){ control=true; console.log("這個Set是"+thisMap); console.log("第3個參數的類型是"+typeof thisMap); } console.log("ok["+now_key+"]="+now_value); });
輸出
這個Set是[object Map]第3個參數的類型是objectok[7]=lzhok[8.5]=isok[666阿]=rubbishok[-30]=sbok[250]=big sb dog