js-人生不過一場絢爛循環

有規律json數組:

var packJson = [ {"name": "nikita", "password": "1111"}, {"name": "tony", "password": "2222"} ]; for (var p in packJson) {//遍歷json數組時,這麼寫p為索引,0,1 alert(packJson[p].name + " " + packJson[p].password); } 複製代碼

1.5 for...of 循環

ES6 借鑑 C++、Java、C# 和 Python 語言,引入了for...of循環,作為遍歷所有數據結構的統一的方法。

一個數據結構只要部署了Symbol.iterator屬性,就被視為具有iterator接口,就可以用for...of循環遍歷它的成員。也就是說,for...of循環內部調用的是數據結構的Symbol.iterator方法。for...of循環可以使用的範圍包括數組、Set和Map結構、某些類似數組的對象(比如arguments對象、DOM NodeList 對象)、後文的 Generator 對象,以及字符串。

下面我們對一些數據結構進行遍歷:

1.5.1 數組

var arr = ['a','b','c','d']; for(let i in arr){ console.log(i);//0 1 2 3 } for(let j of arr){ console.log(j);//a b c d } var iterator = arr.entries(); for(let j of iterator){ console.log(j);//[0,"a"] [1,"b"] [2,"c"] [3,"d"] } var iterator = arr.keys(); console.log(iterator); for(let j of iterator){ console.log(j);//0 1 2 3 } 複製代碼

上面代碼表明,for...in循環讀取鍵名,for...of循環讀取鍵值。如果要通過for...of循環,獲取數組的索引,可以藉助數組實例的entries方法和keys方法。

1.5.2 Set和Map結構

//Set 結構 var newSet = new Set(["a","b","c","c"]); for(var e of newSet){ console.log(e);//a b c } // Map結構 var es6 = new Map(); console.log(es6); es6.set('yaoyao',1); es6.set('bubu','2'); es6.set('fengfeng','last'); for(var [name,value] of es6){//用name和value接受鍵名和鍵值 console.log(name+':'+value);//yaoyao:1 bubu:2 fengfeng:last } 複製代碼

上面代碼演示瞭如何遍歷 Set結構和Map結構。值得注意的地方有兩個,首先,遍歷的順序是按照各個成員被添加進數據結構的順序。其次,Set結構遍歷時,返回的是一個值,而Map結構遍歷時,返回的是一個數組,該數組的兩個成員分別為當前Map成員的鍵名和鍵值。

1.5.3 類似數組的對象

類似數組的對象包括好幾類。下面是for...of循環用於字符串、DOM NodeList 對象、arguments對象的例子。

// 字符串 var str = 'GREAT'; for(let s of str){ console.log(s);//G R E A T } // DOM NodeList對象 let paras = document.querySelectorAll('p'); for(let p of paras){ console.log(p);//打印出所有p標籤 p.classList.add('addClass'); } // arguments對象 function printArgs(){ for(let x of arguments){ console.log(x); } } printArgs([1,2],"1",{"a":3});//[1,2] "1" {"a":3} 複製代碼

1.6 Map()循環

map方法將數組的所有成員依次傳入參數函數,然後把每一次的執行結果組成一個新數組返回,並且不會改變原數組。

var numbers = [1,2,3]; var newNumbers = numbers.map(function(i){ return i+1; }) console.log(newNumbers);//[2,3,4] console.log(numbers);//[1,2,3] 複製代碼

map方法接受一個函數作為參數,該函數調用時,map方法向它傳入三個參數:當前值,當前下標和數組本身。

var newMap = [2,3,4].map(function(item,index,arr){ return item*index; }) console.log(newMap);//[0,3,8] 複製代碼

此外,map方法還可以接受第二個參數,用來綁定回調函數內部的this變量,將回調函數內部的this對象,指向第二個參數,間接操作這個參數(一般是數組)。

var arr = ['a','b','c','d']; var newArgs = [1,2].map(function(i){ return this[i]; },arr); console.log(newArgs);//["b","c"] 複製代碼

上面代碼通過map方法的第二個參數,將回調函數內部的this對象,指向arr數組。間接操作了數組arr;接下來講的forEach同樣具有這個功能。

1.7 forEach()循環

forEach方法與map方法很相似,也是對數組的所有成員依次執行參數函數。但是,forEach方法不返回值,只用來操作數據。也就是說,如果數組遍歷的目的是為了得到返回值,那麼使用map方法,否則使用forEach方法。forEach的用法與map方法一致,參數是一個函數,該函數同樣接受三個參數:當前值、當前下標、數組本身。

[4,5,6].forEach(function(ele,index,arr){ console.log(index+':'+ele);//0:4 1:5 2:5 }) 複製代碼

此外,forEach循環和map循環一樣也可以用綁定回調函數內部的this變量,間接操作其它變量(參考上面的map()循環例子)。

1.8 filter()過濾循環

filter方法用於過濾數組成員,滿足條件的成員組成一個新數組返回。它的參數是一個函數,所有數組成員依次執行該函數,返回結果為true的成員組成一個新數組返回。該方法不會改變原數組。

var newFilter = [1,2,3,4,5,6].filter(function(i){ return i>2 }) console.log(newFilter);//[3,4,5,6] var arr = [0,1,'a',false,null,undefined]; var arrFilter = arr.filter(Boolean); console.log(arrFilter);//[1,"a"] 複製代碼

看起來和Map()循環沒什麼區別,那麼比較一下可以發現map方法內部使用判斷語句時滿足返回true,不滿足返回false。

var newFilter = [1,2,3,4,5,6].map(function(i){ return i>2 }) console.log(newFilter);//[false, false, true, true, true, true] 複製代碼

filter方法的參數函數也可以接受三個參數:當前值,當前下標和數組本身。

var allFilter = [1,2,3,4,5].filter(function(ele,index,arr){ return index % 2 === 0; }) console.log(allFilter);//[1,3,5] 複製代碼

filter方法也可以接受第二個參數,用來綁定參數函數內部的this變量。

var obj = {MAX:3}; var myFilter = function(item){ return item > this.MAX; } var arr = [2,8,3,4,1,3,2,9]; var newFilter = arr.filter(myFilter,obj); console.log(newFilter);//[8,4,9] 複製代碼

1.9 some()、every()循環遍歷,統計數組是否滿足某個條件

這兩個方法類似“斷言”(assert),返回一個布爾值,表示判斷數組成員是否符合某種條件。它們接受一個函數作為參數,所有數組成員依次執行該函數。該函數接受三個參數:當前值、當前下標和數組本身,然後返回一個布爾值。

1.9.1 some()

只要有一個成員滿足條件,則整體返回true;反言之,沒有任何一個成員滿足條件,則整體返回false。

var arr = [1,2,3,4,5]; var newSome = arr.some(function(i){ return i >= 3; }) console.log(newSome);//true 複製代碼

1.9.2 every()

所有成員都滿足條件,則整體返回true;反言之,只要有一個成員不滿足條件,則整體返回false。

var arr = [1,2,3,4,5]; var newEvery = arr.every(function(i){ return i>=3; }) console.log(newEvery);//false 複製代碼

1.10 reduce()和reduceRight()

1.10.1 reduce()

reduce()方法接收一個函數作為累加器,數組中的每個值(從左到右)開始縮減,最終計算為一個值。

[1, 2, 3, 4, 5].reduce(function (a, b) { console.log(a, b); return a + b; }) // 1 2 // 3 3 // 6 4 // 10 5 //最後結果:15 複製代碼

場景: 統計一個數組中有多少個不重複的單詞

使用for循環

var arr = ['apple','orange','apple','orange','pear','orange']; function getWordCnt(){ var obj = {}; for(var i=0,l=arr.length;i

reduce(callback, initialValue)會傳入兩個變量。回調函數(callback)和初始值(initialValue)。假設函數它有個傳入參數,prev和next,index和array。prev和next是必填項,index和array是選填項。一般來講prev是從數組中第一個元素開始的,next是第二個元素。但是當你傳入初始值(initialValue)後,第一個prev將是initivalValue,next將是數組中的第一個元素。

var arr = ['apple','orange','apple']; function noPassValue(){ return arr.reduce(function(prev,next){ console.log('prev:',prev); console.log('next:',next); return prev+' '+next; }) } console.log(noPassValue()); console.log('------------------------------'); function passValue(){ return arr.reduce(function(prev,next){ console.log('prev:',prev); console.log('next:',next); prev[next] = (prev[next]+1)||1; return prev; },{}) } console.log(passValue()); 複製代碼

打印結果為:

觀察打印結果不僅可以明顯發現二者區別,還可以發現函數passValue作用可以等同於上面的for循環。1.10.2 reduceRight()

reduceRight的語法以及回調函數的規則和reduce方法是一樣的,區別就是在與reduce是升序,即角標從0開始,而reduceRight是降序,即角標從arr.length-1開始。

反轉字符串:

var word = 'ilovexx'; function AppendToArray(previousValue,currentValue){ return previousValue + currentValue; } var result = [].reduceRight.call(word,AppendToArray,"the "); console.log(result);//the xxevoli 複製代碼

1.11 Object.keys()

Object.keys方法的參數是一個對象,返回一個數組。該數組的成員都是該對象自身的(而不是繼承的)所有屬性名,且只返回可枚舉的屬性。

var obj = { p1: 123, p2: 456 }; console.log(Object.keys(obj)); // ["p1", "p2"] 複製代碼

這個方法是不是有點眼熟,不妨對比一下上面的2.5.1。

1.12 Object.getOwnPropertyNames()


Object.getOwnPropertyNames方法與Object.keys方法類似,也是接受一個對象作為參數,返回一個數組,包含了該對象自身的所有屬性名。但它能返回不可枚舉的屬性。

var a = ['Hello', 'World']; console.log(Object.keys(a) )// ["0", "1"] console.log(Object.getOwnPropertyNames(a)) // ["0", "1", "length"] 複製代碼

二丶使用jQuery的遍歷

2.1 $.grep()篩選遍歷數組

grep()循環能夠遍歷數組,並篩選符合條件的元素,組成新的數組,並返回。

$(function(){ var array = [1,2,3,4,5,6,7,8,9]; var filterarray = $.grep(array,function(value){ return value > 5;//篩選出大於5的 }); console.log(filterarray);//[6,7,8,9] for(var i=0;i

2.2 $.each()篩選遍歷數組或json對象

$.each(anObject,function(name,value) { console.log(name); console.log(value); }); var anArray = ['one','two','three']; $.each(anArray,function(n,value){ console.log(n); console.log(value); }); 複製代碼

2.3 $.inArray()篩選遍歷數組

var anArray = ['a','b','c']; var index = $.inArray('b',anArray); console.log(index,anArray[index]);//1 "b" 複製代碼

2.4 $.map()篩選遍歷數組

var strings = ['0','1','2','3','4','5','6']; var values = $.map(strings,function(val){ var result = new Number(val); return isNaN(result)?null:result }) for(var key in values){ console.log(values[key]); } 複製代碼

jQuery的遍歷方法在日常使用中還是比較少的,因為這幾種方法在js原生中都能找到對應的方法。寫了這麼多發現實戰中還是for循環用的最多,哈哈哈哈哈。。。。。。不過學了這些之後起碼日後遇到循環問題有更多的解決方案,何樂不為呢。

三丶總結——比較——看異同

其實大多數相似方法的對比在文中就已經談過了,此處將map()、forEach()、filter()三個單獨拎出來做個比較:

相同之處:

1.三種循環中途都是無法停止的,總是會將所有成員遍歷完。

2.他們都可以接受第二個參數,用來綁定回調函數內部的this變量,將回調函數內部的this對象,指向第二個參數,間接操作這個參數(一般是數組)。

不同之處:

forEach()循環沒有返回值;map(),filter()循環有返回值。