1. 程式人生 > 實用技巧 >Array、Object、Map、Set的遍歷

Array、Object、Map、Set的遍歷

Array、Object、Map、Set的遍歷一直記得不太清楚,為了方便查詢,做一個總結

一.Array

1.for

1 for(let i = 0; i < arr.length; i++){
2   ...
3 }

2.for in

i表示陣列的索引

1 for(let i in arr) {
2     ...
3 }

3.for of

可以正確響應break、continue和return語句

1 for(let i of arr) {
2     ...
3 }

4.forEcah

遍歷陣列中的每一項,沒有返回值,對原陣列沒有影響,不支援IE

1 arr.forEach(function
(item,index,arr){ 2 ... 3 }

二.Object

1.for in

for in 迴圈是最基礎的遍歷物件的方式,它還會得到物件原型鏈上的屬性

 1 // 建立一個物件並指定其原型,bar 為原型上的屬性
 2 const obj = Object.create({
 3   bar: 'bar'
 4 })
 5 
 6 // foo 為物件自身的屬性
 7 obj.foo = 'foo'
 8 
 9 for (let key in obj) {
10   console.log(obj[key]) // foo, bar
11 }

可以看到物件原型上的屬性也被迴圈出來了

在這種情況下可以使用物件的hasOwnProperty()方法過濾掉原型鏈上的屬性

1 for (let key in obj) {
2   if (obj.hasOwnProperty(key)) {
3     console.log(obj[key]) // foo
4   }
5 }

這時候原型上的 bar 屬性就被過濾掉了

2.Object.keys

Object.keys() 是 ES5 新增的一個物件方法,該方法返回物件自身屬性名組成的陣列,它會自動過濾掉原型鏈上的屬性,然後可以通過陣列的forEach()方法來遍歷

1 Object.keys(obj).forEach((key) => {
2 console.log(obj[key]) // foo 3 })

另外還有Object.values()方法和Object.entries()方法,這兩方法的作用範圍和Object.keys()方法類似

注意:for in迴圈和 object.keys()方法都不會返回物件的不可列舉屬性

如果需要遍歷不可列舉的屬性,需要用Object.getOwnPropertyNames()

3.Object.getOwnPropertyNames()

Object.getOwnPropertyNames()也是 ES5 新增的一個物件方法,該方法返回物件自身屬性名組成的陣列,包括不可列舉的屬性,也可以通過陣列的forEach方法來遍歷

 1 // 建立一個物件並指定其原型,bar 為原型上的屬性
 2 // baz 為物件自身的屬性並且不可列舉
 3 const obj = Object.create({
 4   bar: 'bar'
 5 }, {
 6   baz: {
 7     value: 'baz',
 8     enumerable: false
 9   }
10 })
11 
12 obj.foo = 'foo'
13 
14 // 不包括不可列舉的 baz 屬性
15 Object.keys(obj).forEach((key) => {
16   console.log(obj[key]) // foo
17 })
18 
19 // 包括不可列舉的 baz 屬性
20 Object.getOwnPropertyNames(obj).forEach((key) => {
21   console.log(obj[key]) // baz, foo
22 })

ES2015 新增了 Symbol 資料型別,該型別可以作為物件的鍵,針對該型別 ES2015 同樣新增了Object.getOwnPropertySymbols()方法

4.Object.getOwnPropertySymbols

Object.getOwnPropertySymbols()方法返回物件自身的 Symbol 屬性組成的陣列,不包括字串屬性

1 Object.getOwnPropertySymbols(obj).forEach((key) => {
2   console.log(obj[key])
3 })

什麼都沒有,因為該物件還沒有 Symbol 屬性

 1 // 給物件新增一個不可列舉的 Symbol 屬性
 2 Object.defineProperties(obj, {
 3   [Symbol('baz')]: {
 4     value: 'Symbol baz',
 5     enumerable: false
 6   }
 7 })
 8 
 9 // 給物件新增一個可列舉的 Symbol 屬性
10 obj[Symbol('foo')] = 'Symbol foo'
11 
12 Object.getOwnPropertySymbols(obj).forEach((key) => {
13   console.log(obj[key]) // Symbol baz, Symbol foo
14 })

5.Reflect.ownKeys

Reflect.ownKeys()方法是 ES2015 新增的靜態方法,該方法返回物件自身所有屬性名組成的陣列,包括不可列舉的屬性和 Symbol 屬性

1 Reflect.ownKeys(obj).forEach((key) => {
2   console.log(obj[key]) // baz, foo, Symbol baz, Symbol foo
3 })

對比

方式基本屬性原型鏈不可列舉Symbol
for in
Object.keys()
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Reflect.ownKeys()

結論

這其中只有 for in 迴圈會得到物件原型鏈上的屬性,其它方法都只適用於物件自身的屬性

ES 語言後續新增的新特性不會對以前的程式碼產生副作用,比如在 ES2015 之前就存在的 for in 迴圈,Object.keys() 和 Object.getOwnPropertyNames() 是肯定不會返回 Symbol 屬性的

三.Map、Set

1.for of

Array可以採用下標進行迴圈遍歷,Map和Set就無法使用下標。為了統一集合型別,ES6標準引入了iterable型別,Array、Map、Set都屬於iterable型別。

具有iterable型別的集合可以通過新的for ... of迴圈來遍歷。

 1 var a = ['A', 'B', 'C'];
 2 var s = new Set(['A', 'B', 'C']);
 3 var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
 4 for (var x of a) { // 遍歷Array
 5     alert(x);
 6 }
 7 for (var x of s) { // 遍歷Set
 8     alert(x);
 9 }
10 for (var x of m) { // 遍歷Map
11     alert(x[0] + '=' + x[1]);
12 }

2.forEach

forEach是iterable內建的方法,它接收一個函式,每次迭代就自動回撥該函式。

1 var a = ['A', 'B', 'C'];
2 a.forEach(function (element, index, array) {
3     // element: 指向當前元素的值
4     // index: 指向當前索引
5     // array: 指向Array物件本身
6     alert(element);
7 });

Set與Array類似,但Set沒有索引,因此回撥函式的前兩個引數都是元素本身:

1 var s = new Set(['A', 'B', 'C']);
2 s.forEach(function (element, sameElement, set) {
3     alert(element);
4 });

Map的回撥函式引數依次為valuekeymap本身:

1 var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
2 m.forEach(function (value, key, map) {
3     alert(value);
4 });