這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 for in 和 for of 相對於大家肯定都不陌生,都是用來遍歷屬性的沒錯。那麼先看下麵的一個例子: 例1 const obj = { a: 1, b: 2, c: 3 } for (let i in obj) { console.l ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
for in 和 for of 相對於大家肯定都不陌生,都是用來遍歷屬性的沒錯。那麼先看下麵的一個例子:
例1
const obj = { a: 1, b: 2, c: 3 } for (let i in obj) { console.log(i) // a // b // c } for (let i of obj) { console.log(i) // Uncaught TypeError: obj is not iterable 報錯了 }
以上代碼通過 for in 和 for of 對一個obj對象進行遍歷,for in 正常的獲取了對象的 key值,分別列印 a、b、c,而 for of卻報錯了。
例2:
以上是遍歷對象,下麵再看一個遍曆數組的例子。
const arr = ['a', 'b', 'c'] // for in 迴圈 for (let i in arr) { console.log(i) // 0 // 1 // 2 } // for of for (let i of arr) { console.log(i) // a // b // c }
以上代碼是對一個數組進行遍歷, for in 返回的值為 0、1、2,這不是數組的下標嗎? 而 for of 返回的是 a、b、c,這一次沒有報錯,為什麼呢?
例3
const arr = ['a', 'b'] // 手動給 arr數組添加一個屬性 arr.name = 'qiqingfu' // for in 迴圈可以遍歷出 name 這個鍵名 for (let i in arr) { console.log(i) // a // b // name }
for in 的特點
結合上面的兩個例子,分析得出:
-
for ... in 迴圈返回的值都是數據結構的 鍵值名。
-
遍歷對象返回的對象的key值,遍曆數組返回的數組的下標(key)。
-
for ... in 迴圈不僅可以遍曆數字鍵名,還會遍歷原型上的值和手動添加的其他鍵。如——例3
-
特別情況下, for ... in 迴圈會以看起來任意的順序遍歷鍵名
(為什麼說看起來,其實也是有規律的,這個就要扯到 常規屬性和 排序屬性,想深入學習的可以看讀李老課程引發的思考之JS設計思想篇
這裡可以簡單說一下
1.什麼是對象中的 常規屬性和 排序屬性
function Foo() { this[100] = 'test-100' this[1] = 'test-1' this["B"] = 'bar-B' this[50] = 'test-50' this[9] = 'test-9' this[8] = 'test-8' this[3] = 'test-3' this[5] = 'test-5' this["A"] = 'bar-A' this["C"] = 'bar-C' } var bar = new Foo() for(key in bar){ console.log(`index:${key} value:${bar[key]}`) }
在上⾯這段代碼中,我們利⽤構造函數Foo創建了⼀個bar對象,在構造函數中,我們給bar對象設置了很多 屬性,包括了數字屬性和字元串屬性,然後我們枚舉出來了bar對象中所有的屬性,並將其⼀⼀列印出來, 下⾯就是執⾏這段代碼所列印出來的結果
index:1 value:test-1 index:3 value:test-3 index:5 value:test-5 index:8 value:test-8 index:9 value:test-9 index:50 value:test-50 index:100 value:test-100 index:B value:bar-B index:A value:bar-A index:C value:bar-C
觀察這段列印出來的數據,我們發現列印出來的屬性順序並不是我們設置的順序,我們設置屬性的時候是亂 序設置的,⽐如開始先設置100,然後有設置了1,但是輸出的內容卻⾮常規律,總的來說體現在以下兩 點:
設置的數字屬性被最先列印出來了,並且按照數字⼤⼩的順序列印的;
設置的字元串屬性依然是按照之前的設置順序列印的,⽐如我們是按照B、A、C的順序設置的,列印出來,依然是這個順序。
之所以出現這樣的結果,是因為在ECMAScript規範中定義了 「數字屬性應該按照索引值⼤⼩升序排列,字元 串屬性根據創建時的順序升序排列。」在這⾥我們把對象中的數字屬性稱為 「排序屬性」,在V8中被稱為 elements,字元串屬性就被稱為 「常規屬性」, 在V8中被稱為 properties。在V8內部,為了有效地提升存儲和訪問這兩種屬性的性能,分別使⽤了兩個 線性數據結構來分別保存排序 屬性和常規屬性,具體結構如下圖所⽰:
在elements對象中,會按照順序存放排序屬性,properties屬性則指向了properties對 象,在properties對象中,會按照創建時的順序保存了常規屬性。
總結一句: for in 迴圈特別適合遍歷對象。
for of 特點
for of 迴圈用來獲取一對鍵值對中的值,而 for in 獲取的是 鍵名
一個數據結構只要部署了 Symbol.iterator 屬性, 就被視為具有 iterator介面, 就可以使用 for of迴圈。
例1這個對象,沒有 Symbol.iterator這個屬性,所以使用 for of會報 obj is not iterable
for of 不同與 forEach, 它可以與 break、continue和return 配合使用,也就是說 for of 迴圈可以隨時退出迴圈。
提供了遍歷所有數據結構的統一介面
哪些數據結構部署了 Symbol.iteratoer屬性了呢?
只要有 iterator 介面的數據結構,都可以使用 for of迴圈。
-
數組 Array
-
Map
-
Set
-
String
-
arguments對象
-
Nodelist對象, 就是獲取的dom列表集合
-以上這些都可以直接使用 for of 迴圈。 凡是部署了 iterator 介面的數據結構也都可以使用數組的 擴展運算符(...)、和解構賦值等操作。
我也想讓對象可以使用 for of迴圈怎麼辦?使用 Object.keys() 獲取對象的 key值集合後,再使用 for of
以例1為例
const obj = { a: 1, b: 2, c: 3 } for (let i of Object.keys(obj)) { console.log(i) // 1 // 2 // 3 }