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
的回撥函式引數依次為value
、key
和map
本身:
1 var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]); 2 m.forEach(function (value, key, map) { 3 alert(value); 4 });