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());
複製代碼

打印結果為:

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

觀察打印結果不僅可以明顯發現二者區別,還可以發現函數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()循環有返回值。


分享到:


相關文章: