前言
日常開發中,數組或是對象的遍歷是一個經常會遇到的事情,關於遍歷,其實Js提供了很多方法,但是對於他們之間的區別卻理解的不是很透徹,通常情況就是抓起來一個forEach就用。爲了提高代碼質量,我認爲有必要深入瞭解一下不同遍歷的特點。當然,本文不作太多深入講解,只是就各種的特點進行整理展示。
一、for..in
,for..of
,forEach
1、遍歷對象
for..in
:輸出 索引
let obj = {
a:1,
b:2,
c:3
}
for(let i in obj){
console.log(i)
}
//a
//b
//c
for..of
&& forEach
:不支持
2、遍歷數組
let arr = [1,'參數2',3]
for..in
:輸出 索引
for(let i in arr){
console.log(i)
}
//0
//1
//2
for..in
也可以通過 arr[i]
的方式輸出值
for..of
:輸出 值
for(let i of arr){
console.log(i)
}
//1
//參數2
//3
forEach
:輸出 值&索引
arr.forEach((item,index)=>{
console.log(item,index)
}}
//1 0
//參數2 1
//3 2
3、遍歷的數組或對象包含原型屬性或者自定義屬性時
let arr = [1,'參數2',3]
arr.attr='attr'
Array.prototype.arrCustom = function() {};
for..in
:全部輸出
for(let i in arr){
console.log(i)
}
//0
//1
//2
//attr
//arrCustom
當然也可以通過 hasOwnProperty
進行一些優化,但是自定義的屬性依舊會輸出
for(let i in arr){
if (arr.hasOwnProperty(i)) {
console.log(i);
}
}
//0
//1
//2
//attr
for..of
& forEach
:不受影響,輸出正常
4、遍歷時能否中斷循環
let arr = [1,3,5,7,9]
for..in
:無法中斷
for..of
:可以使用break
中斷
for(let i of arr){
console.log(i);
if (i==5) {
break;
}
}
//1
//3
//5
forEach
:無法中斷
arr.forEach((item,i)=>{
console.log(item);
if (item==5) {
return false;
}
})
//1
//3
//5
//7
//9
二、一些for..of
特有的功能
1、迭代字符串
let str = 'mystr'
for(let i of str){
console.log(i);
}
//m
//y
//s
//t
//r
2、迭代arguments類數組對象
3、迭代類DOM集合
無需[].slice.call()
,也不需要Array.from()
進行數組轉化
4、迭代類型數組
let typeArr = new Uint8Array([0x00, 0xff]);
for (let value of typeArr) {
console.log(value);
}
// 0
// 255
5、迭代Map
let mapData = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (let [key, value] of mapData) {
console.log(value);
}
// 1
// 2
// 3
6、迭代Set
let setData = new Set([1, 1, 2, 2, 3, 3]);
for (let value of setData) {
console.log(value);
}
// 1
// 2
// 3
等等。
總結:
for..of
是ES6中新增的語法,相對來說應用場景會更豐富一些,但是兼容性的話想對弱一些,使用的時候應酌情考慮
不考慮兼容性的情況下:
- 純對象的遍歷======
for..in
- 數組遍歷,不需要知道索引時======
for..of
- 需要索引=====
forEach
因爲for..of
可以中斷,所以數組遍歷時更推薦使用。
番外:
除了以上三個重點列出的遍歷方法外,其實JS中還有很多其他的遍歷方法,只是應用場景稍有不同。
對象遍歷
除了以上的for..in
,還有下面的一些方法也可以實現
var mySymbol = Symbol();
let myObj = {
name:'seven',
age:18,
[mySymbol]:'Hello!'//Symbol屬性
}
Object.prototype.hobby = 'music';
myObj.sex='female'
-
Obeject.keys(obj)
可以返回一個數組,包括對象自身的所有可枚舉屬性,不包括繼承的屬性和Symbol屬性
Object.keys(myObj)
//["name", "age", "sex"]
-
Object.getOwnPropertyNames(obj)
返回一個數組,包含對象自身的所有屬性,不含Symbol屬性,包括不可枚舉屬性
Object.getOwnPropertyNames(myObj)
//["name", "age", "sex"]
-
Object.getOwnPropertySymbols(obj)
返回一個數組,包含對象自身的所有Symbol屬性
Object.getOwnPropertySymbols(myObj)
//[Symbol()]
-
Reflect.ownKeys(obj)
返回一個數組,包含對象自身的所有屬性,不管屬性名是Symbol或字符串,也不管是否可枚舉
Reflect.ownKeys(myObj)
//["name", "age", "sex", Symbol()]
數組遍歷
Array.every()
:測試數組的所有元素是否都通過了指定函數的測試
function isBelowThreshold(currentValue) {
return currentValue < 40;
}
var array1 = [1, 30, 39, 29, 10, 13];
console.log(array1.every(isBelowThreshold))
// true
Array.some()
:檢測數組中的元素是否滿足指定條件
- 如果有一個元素滿足條件,則表達式返回true , 剩餘的元素不會再執行檢測。
- 如果沒有滿足條件的元素,則返回false。
tip:不會改變原始數組
var ages = [3, 10, 18, 20];
function checkAdult(age) {
return age >= 18;
}
ages.some(checkAdult)
//true
Array.filter()
:創建一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素
tip:不會改變原始數組
var ages = [32, 33, 16, 40];
function checkAdult(age) {
return age >= 18;
}
ages.filter(checkAdult)
//[32, 33, 40]
Array.map()
:返回一個由原數組中的每個元素調用一個指定方法後的返回值組成的新數組
tip:不會改變原始數組
var ages = [32, 33, 16, 40];
function checkAdult(age) {
return age + 1
}
ages.map(checkAdult)
//[33, 34, 17, 41]
Array.reduce()
:接收一個函數作爲累加器,數組中的每個值(從左到右)開始縮減,最終計算爲一個值
tip:不會改變原始數組
var numbers = [65, 44, 12, 4];
function getSum(total, num) {
return total + num;
}
numbers.reduce(getSum);
//125
numbers.reduce(getSum,2);
//127
本文關於for..in
、for..of
、forEach
的對比參考自張鑫旭大神的文章,傳送門在這裏:看,for…in和for…of在那裏吵架!,文風還是挺詼諧幽默的,推薦一看!