在某個祕密的季節,青春逝去,不復重來。或許它只是殘留在清澈陽光下的某一個不經意的思緒碎片,但它依然能讓咱們的眼睛裏泛出淡淡的光來。javascript
額,很差意思,走錯片場了,今日不談李易安,且論循環。html
本文講的是js的循環遍歷並不是事件循環機制,立意不深,大神蜻蜓點水,衆生可搶沙發。java
while語句包括一個循環條件和一段代碼塊,只要條件爲真,就不斷循環執行代碼塊。先判斷後執行
。es6
var num = 1;//1.聲明循環變量
while (num<=10){//2.判斷循環條件
document.write(num+" ");//3.執行循環體
num++;//4.跟新循環變量
}
複製代碼
do...while循環與while循環相似,惟一的區別就是先運行一次循環體,而後判斷循環條件。即先執行後判斷
。json
var num = 10;
do{
document.write(num+" ");
num--;
}while(num>=0);
document.write(num);//-1
複製代碼
for循環有三個表達式:①聲明循環變量;②判斷循環條件;③更新循環變量;先判斷後執行
,與while相同。數組
for(var num=0;num<10;num++){
document.write(num+" ");
}
複製代碼
for...in 循環主要用於遍歷對象。bash
var obj = {a:1,b:2,c:3};
for(var i in obj){
console.log('鍵名:'+i);
console.log('鍵值:'+obj[i]);
}
複製代碼
for...in 循環,遍歷時不只能讀取對象自身上面的成員屬性,也能延續原型鏈遍歷出對象的原型屬性,可使用hasOwnProperty
判斷一個屬性是否是對象自身上的屬性。obj.hasOwnProperty(keys)==true
表示這個屬性是對象的成員屬性,而不是原型屬性。數據結構
var person = {name:'小夏'};
for(var key in person){
if(person.hasOwnProperty(key)){
console.log(key);//name
}
}
複製代碼
再聊一點:遍歷json對象app
無規律json數組:函數
var json = [{qwer:'姚姚',a:'is',b:1}, {ob:'da',tp:'sb'}];
for(var i=0,l=json.length;i<l;i++){//此處長度用變量保存下來可節約資源的消耗
for(var key in json[i]){
alert(key+':'+json[i][key]);
}
}
複製代碼
有規律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);
}
複製代碼
ES6 借鑑 C++、Java、C# 和 Python 語言,引入了for...of循環,做爲遍歷全部數據結構的統一的方法。
一個數據結構只要部署了
Symbol.iterator
屬性,就被視爲具備iterator
接口,就能夠用for...of循環遍歷它的成員。也就是說,for...of循環內部調用的是數據結構的Symbol.iterator
方法。for...of循環可使用的範圍包括數組、Set和Map結構、某些相似數組的對象(好比arguments
對象、DOM NodeList
對象)、後文的Generator
對象,以及字符串。
下面咱們對一些數據結構進行遍歷:
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
方法。
//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成員的鍵名和鍵值。
相似數組的對象包括好幾類。下面是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}
複製代碼
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一樣具備這個功能。
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()循環例子)。
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]
複製代碼
這兩個方法相似「斷言」(assert),返回一個布爾值,表示判斷數組成員是否符合某種條件。它們接受一個函數做爲參數,全部數組成員依次執行該函數。該函數接受三個參數:當前值、當前下標和數組自己,而後返回一個布爾值。
只要有一個成員知足條件,則總體返回true;反言之,沒有任何一個成員知足條件,則總體返回false。
var arr = [1,2,3,4,5];
var newSome = arr.some(function(i){
return i >= 3;
})
console.log(newSome);//true
複製代碼
全部成員都知足條件,則總體返回true;反言之,只要有一個成員不知足條件,則總體返回false。
var arr = [1,2,3,4,5];
var newEvery = arr.every(function(i){
return i>=3;
})
console.log(newEvery);//false
複製代碼
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<l;i++){
var item = arr[i];
obj[item] = (obj[item]+1)||1;
//第一次遍歷obj.apple是undefined,因此obj.apple取1;
//第二次遍歷obj.orange是undefined,因此obj.orange取1;
//第三次遍歷obj.apple已是1了,因此obj.apple = 1+1;······
}
return obj;
}
console.log(getWordCnt());//{apple: 2, orange: 3, pear: 1}
複製代碼
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());
複製代碼
打印結果爲:
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
複製代碼
Object.keys方法的參數是一個對象,返回一個數組。該數組的成員都是該對象自身的(而不是繼承的)全部屬性名,且只返回可枚舉的屬性。
var obj = {
p1: 123,
p2: 456
};
console.log(Object.keys(obj)); // ["p1", "p2"]
複製代碼
這個方法是否是有點眼熟,不妨對比一下上面的2.5.1。
Object.getOwnPropertyNames方法與Object.keys方法相似,也是接受一個對象做爲參數,返回一個數組,包含了該對象自身的全部屬性名。但它能返回不可枚舉的屬性。
var a = ['Hello', 'World'];
console.log(Object.keys(a) )// ["0", "1"]
console.log(Object.getOwnPropertyNames(a)) // ["0", "1", "length"]
複製代碼
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<filterarray.length;i++){
alert(filterarray[i]);
}
for (key in filterarray){
alert(filterarray[key]);
}
})
複製代碼
$.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);
});
複製代碼
var anArray = ['a','b','c'];
var index = $.inArray('b',anArray);
console.log(index,anArray[index]);//1 "b"
複製代碼
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()循環有返回值。
你還在用for循環大法麼?
js的15種循環遍歷,你掌握了幾種?
深刻了解 JavaScript 中的 for 循環
JS中的循環---最全的循環總結