JS遍歷物件屬性的7種方式

十方發表於2022-06-19

在有些開發場景下,可能需要獲取一個物件的所有屬性欄位名,或者同時獲取屬性欄位名和屬性值,比如下面的一個普通的物件:

let obj = {
    type: 1,
    keyword: 'js'
}

這個 obj 物件只有兩個屬性欄位:type 和 keyword,屬性值為 1 和 js,實際過程中的物件可能更加複雜,欄位也會更多。

對於遍歷一個物件的屬性,最容易想到的就是使用 for 迴圈 這種方式,因為它更直接,而且平時使用也是比較多,除了直接使用 for 迴圈這種方式外,還有其他的幾種方式,這裡主要分為三大類,共7中方式:

  • for迴圈方式

    • for...in
    • for...of
  • Object方法

    • Object.keys()
    • Object.entries()
    • Object.getOwnPropertyNames()
    • Object.getOwnPropertySymbols()
  • Reflect方法

    • Reflect.ownKeys()

1、for...in

for...in 語句可以用來迴圈一個物件所有可列舉的屬性,包括繼承的屬性,下面的程式碼是用來列印 obj 物件所有的屬性欄位和屬性值:

let obj = {type: 1, keyword: "js"};
for (let key in obj) {
    console.log(key, obj[key])
}

輸出結果如下:

type 1
keyword js

2、for...of

for...of 語句主要用來迴圈一個可迭代物件的屬性,要成為可迭代物件, 一個物件必須實現 @@iterator 方法,這意味著物件(或者它原型鏈上的某個物件)必須有一個鍵為 @@iterator 的屬性,可通過常量 Symbol.iterator 訪問該屬性。

對於普通的物件,其實並不是可迭代物件,如果直接使用 for...of 遍歷的話,會報錯的,下面來測試一下:

let obj = {type: 1, keyword: "js"};
for (let key of obj) {
    console.log(key, obj[key])
}

執行後,出現下面的錯誤,直接提示 obj 不是可迭代物件,如下:

那麼如何使用 for...of 來遍歷物件屬性呢,首先需要做的就是將 obj 物件轉換成一個可迭代物件,這裡可以藉助 Object.keys() 方法,調整後的程式碼如下:

let obj = {type: 1, keyword: "js"};
for (let key of Object.keys(obj)) {
    console.log(key, obj[key])
}

輸出結果如下:

type 1
keyword js

3、Object.keys()

在上面的 for...of 語句中,已經使用了 Object.keys() 方法將 obj 物件轉換成了一個可迭代物件,其實也可以直接使用 Object.keys() 方法來遍歷一個物件的屬性,先來看看它的定義

Object.keys() 方法會返回一個由一個給定物件的自身可列舉屬性組成的陣列,陣列中屬性名的排列順序和正常迴圈遍歷該物件時返回的順序一致

測試程式碼如下:

let obj = {type: 1, keyword: "js"};
Object.keys(obj).forEach(key => console.log(key, obj[key]))

輸出結果如下:

type 1
keyword js

4、Object.entries()

除了上述的 Object.keys() 方法,還有使用 Object.entries() 方法,它的定義如下:

Object.entries() 方法返回一個給定物件自身可列舉屬性的鍵值對陣列,其排列與使用 for...in 迴圈遍歷該物件時返回的順序一致(區別在於 for-in 迴圈還會列舉原型鏈中的屬性)。

測試程式碼如下:

let obj = {type: 1, keyword: "js"};
Object.entries(obj).forEach(item => console.log(item[0], item[1]))

輸出結果如下:

type 1
keyword js

這個方法和 Object.keys() 方法的區別在於,它迴圈返回的結果是鍵值對,而 Object.keys() 返回的只是物件的屬性名稱,並不包括值,如果只是想遍歷一個物件的所有屬性值,那麼可以使用另外的一個方法:Object.values()

5、Object.getOwnPropertyNames()

這個方法也可以用來遍歷一個物件的屬性,它的定義如下:

Object.getOwnPropertyNames() 方法返回一個由指定物件的所有自身屬性的屬性名(包括不可列舉屬性但不包括 Symbol 值作為名稱的屬性)組成的陣列。

下面來看看測試程式碼:

let obj = {type: 1, keyword: "js"};
Object.getOwnPropertyNames(obj).forEach(key => console.log(key, obj[key]))

輸出結果如下:

type 1
keyword js

6、Object.getOwnPropertySymbols()

這個方法也可以用來遍歷一個物件的屬性,它的定義如下:

Object.getOwnPropertySymbols() 方法返回一個給定物件自身的所有 Symbol 屬性的陣列。

從它的定義可以看出,它只能用於遍歷 Symbol 屬性,不能遍歷非Symbol 屬性,對於一個普通物件,如果沒有Symbol 屬性,那麼其實是無法使用該方法來遍歷的,具體測試程式碼如下:

let obj = {type: 1, keyword: "js"};
Object.getOwnPropertySymbols(obj).forEach(key => console.log(key, obj[key]))

無法輸出任何結果,因為 obj 物件沒有任何 Symbol 屬性,使用 Object.getOwnPropertySymbols(obj) 方法,只會得到一個空陣列。

下面來定義一個包含 Symbol 屬性的物件,同時來遍歷一下這個物件的屬性:

let type = Symbol('type');
let keyword = Symbol('keyword');
let symbolObj = {};
symbolObj[type] = 1;
symbolObj[keyword] = 'js';
symbolObj['name'] = 'javascript';

Object.getOwnPropertySymbols(symbolObj).forEach(key => console.log(key, symbolObj[key]));

輸出的結果如下:

Symbol(type) 1
Symbol(keyword) 'js'

雖然 symbolObj 物件有三個屬性,但是隻會輸出其中的兩個 Symbol 屬性:Symbol(type) 和 Symbol(keyword) 屬性,而不會輸出普通屬性 name。

7、Reflect.ownKeys()

除了使用 Object 提供的靜態方法外,還可以使用 Reflect.ownKeys() 方法來遍歷物件屬性,首先來看看 Reflect 物件是什麼:

Reflect 是一個內建的物件,它提供攔截 JavaScript 操作的方法,不能通過new 運算子對其進行呼叫,或者將Reflect物件作為一個函式來呼叫,Reflect的所有屬性和方法都是靜態的(就像Math物件)。

再來看看 Reflect.ownKeys() 方法的定義

靜態方法 Reflect.ownKeys() 返回一個由目標物件自身的屬性鍵組成的陣列。

從它的定義可以看出,它和 Object.keys() 方法差不多,測試程式碼如下:

let obj = {type: 1, keyword: "js"};
Reflect.ownKeys(obj).forEach(key => console.log(key, obj[key]))

輸出結果如下:

type 1
keyword js

參考資料

相關文章