js遍歷對象的幾種方法


作為經常使用對象的我們,在有些業務場景下需要對對象的屬性進行遍歷,下面我總結了幾種常用的 JS 遍歷對象屬性的方法。

 本文關聯文章之js判斷對象中是否含有某個屬性

 

太長不看版:

JS 遍歷對象的主要方法有  for...in 、Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()、Reflect.ownKeys()。

備注:可枚舉:屬性的 enumerable 值為 true;自身屬性:自有的,不是從原型上繼承來的屬性。

  • 遍歷對象所有的可枚舉屬性(自有的+繼承的屬性),使用 for...in

  • 遍歷對象自有的所有可枚舉屬性(非繼承屬性),使用 Object.keys() 或 for...in + Objec.hasOwnProperty()

  • 獲取對象所有繼承屬性(非自有屬性),可以使用 for...in + Object.keys()

  • 遍歷對象自有的所有可枚舉和不可枚舉屬性(非繼承屬性),使用 Object.getOwnPropertyNames()

  • 獲取對象自有的所有可枚舉、不可枚舉屬性和繼承屬性,使用 for...in + Object.getOwnPropertyNames(obj) 或 for...in + Object.keys() + Object.getOwnPropertyNames(obj)

如果想了解更多詳細內容,請往下看:

 

一、for...in

for...in 用於以任意順序遍歷對象所有的可枚舉屬性(包括對象自身的和繼承的可枚舉屬性,不含 Symbol 屬性)。

let obj = {
    name: 'Scarlett',
    age: 37,
    [Symbol()]: 'Johansson'
}
for (let key in obj) {
    console.log(key) // name age
}
​
// 在原型上添加一個可枚舉屬性
Object.prototype.nationality = 'America'// 在obj對象上添加一個不可枚舉屬性
Object.defineProperty(obj, 'occupation', {
    value: 'actress',
    enumerable: false
})
for (let key in obj) {
    console.log(key, obj[key])
}
/* 輸出結果:包含對象自身的可枚舉屬性和原型上的可枚舉屬性
name Scarlett
age 37
nationality America
*/

想必大家對這個語法並不陌生,但在很多實際業務場景中是對屬性的精准使用,而不是直接這樣用。

我們知道對象具有的屬性可能是多來源的,可能是自身創建的,可能繼承自原型,也可能繼承自構造函數......其中我們可以通過 Object.hasOwnProperty() 來判斷這個屬性是否是自有屬性,該方法會過濾掉那些繼承來的屬性。

for...in 循環可以訪問到對象具有的所有可枚舉屬性,而對象的不可枚舉屬性則是由屬性的 enumerable 值決定的,比如 constructor,length 屬性等都不能被 for...in 訪問到。方法 Object.propertyIsEnumerable() 可以判斷此對象是否包含某個屬性,並且這個屬性是否可枚舉(通過原型繼承的屬性除外)。

 

二、for...of

for...of 是 ES6 新增的遍歷方式,它為不同的數據結構提供了統一的遍歷機制。任何數據結構只要實現了 Iterator 接口的,都可以被遍歷。關於 Iterator 接口可以參考 這里

for...of 循環可以使用的范圍包括Array、Set 和 Map 結構、類數組對象(比如arguments 對象、DOM NodeList 對象)、字符串等。

1. 類數組對象

以下是 for...of 循環字符串、arguments 對象、DOM 元素集合的例子:

// 字符串
let str = "hello";
for (let s of str) {
    console.log(s); // h e l l o
}

// DOM元素集合
let domList = document.querySelectorAll("p");
for (let p of domList) {
    p.classList.add("test");
}

// arguments對象
function printArgs() {
    for (let arg of arguments) {
        console.log(arg);
    }
}
printArgs('a', 'b'); // 'a'  'b'

雖然不是所有的類數組對象都具有 Iterator 接口,但一個簡便的解決方法,就是使用 Array.from() 方法將一個類似數組或可迭代對象轉為一個淺拷貝的數組實例。

let arrayLike = { length: 2, 0: 'a', 1: 'b' };

// 報錯 TypeError: arrayLike is not iterable
for (let key of arrayLike) {
    console.log(key);
}

// 正確執行
for (let key of Array.from(arrayLike)) {
    console.log(key);  // 'a' 'b'
}
2. 普通對象

對於普通的對象,for...of 結構不能直接使用,會報錯,必須部署了 Iterator 接口后才能使用。

let obj = {
    name: 'Scarlett',
    age: 37
}

// 報錯 TypeError: obj is not iterable
for (let key of obj) {
    console.log(key);
}

// 解決:使用Object.keys()方法將對象的鍵名生成一個數組,然后遍歷。
for (var key of Object.keys(obj)) {
    console.log(key);
}

 

三、Object.keys()

Object.keys() ES5 新增的一個對象方法,該方法接收一個對象為參數,返回一個數組,包含該對象自有的可枚舉屬性(不含繼承的和Symbol屬性),數組中屬性名的排列順序和正常循環遍歷該對象時返回的順序一致 。

let obj = {
    name: 'Scarlett',
    age: 37,
    [Symbol()]: 'Johansson'
}

// 在原型上添加一個可枚舉屬性
Object.prototype.nationality = 'America'

// 在obj對象上添加一個不可枚舉屬性
Object.defineProperty(obj, 'occupation', {
    value: 'actress',
    enumerable: false
})

// 獲取對象自有的可枚舉屬性
Object.keys(obj).map(key => {
    console.log(key);   // name  age
})

console.log(Object.entries(obj)); // [["name", "Scarlett"], ["age", 37]]
console.log(Object.values(obj)); // ["Scarlett", 37]

注意:該方法如果參數不是一個對象,將被強制轉換為一個對象。

使用 for...in 結合 Object.hasOwnProperty() 也能達到獲取自有的可枚舉屬性或繼承屬性的目的。

// 得到所有可枚舉屬性(自有的和繼承的屬性)
for (let key in obj) {
    // 過濾掉繼承屬性
    if (obj.hasOwnProperty(key)) {
        console.log(key);
    }
}

另外:

    • Object.entries() 返回指定對象自身的可枚舉屬性的鍵值對(不含繼承的和Symbol屬性)數組;

    • Object.values() 返回指定對象自身的所有可枚舉屬性的值(不含繼承的和Symbol屬性)組成的數組;

這兩個方法的使用范圍和 Object.keys() 方法類似,這里不再詳細說明。

 

四、Object.getOwnPropertyNames()

Object.getOwnPropertyNames() 方法接收一個對象為參數,返回該對象所有可枚舉和不可枚舉屬性的屬性名(不含Symbol屬性)組成的數組。

// 接上demo
console.log(Object.getOwnPropertyNames(obj))  // ["name", "age", "occupation"]

綜上,可以拓展出 for...in 結合 Object.getOwnPropertyNames() 獲取對象自有的所有可枚舉、不可枚舉屬性和繼承屬性。

const getAllPropertyNames = (obj) => {
    let props = Object.assign([], Object.getOwnPropertyNames(obj))
    // 得到所有的可枚舉屬性(自有的和繼承的屬性)
    for (let key in obj) {
        // 過濾自有的不可枚舉屬性
        if (!Object.getOwnPropertyNames(obj).includes(key)) {
            props.push(key)
        }
    }
    return props;
};
getAllPropertyNames(obj);  // ["name", "age", "occupation", "nationality"] 

這里也可以使用 for...in + Object.keys() + Object.getOwnPropertyNames(obj) 的方法得到同樣的結果,有興趣的可以自行嘗試。

 

五、Object.getOwnPropertySymbols()

Object.getOwnPropertySymbols() 方法返回指定對象自身所有的Symbol屬性的數組。

// 接上demo
var symbolsArr = Object.getOwnPropertySymbols(obj);
for( let sym of symbolsArr){
    console.log(sym, obj[sym]); // Symbol() "Johansson"
}

// 給對象添加一個不可枚舉的Symbol屬性
Object.defineProperties(obj, {
    [Symbol('aa')]: {
          value: 'localSymbol',
          enumerable: false
     }
})
Object.getOwnPropertySymbols(obj).map(key => {
    console.log(key, obj[key]); // Symbol() "Johansson", Symbol(aa) "localSymbol"
})

 

六、Reflect.ownKeys()

Reflect.ownKeys() 返回指定對象自身的所有屬性(包含不可枚舉屬性和Symbol屬性)組成的數組。它的返回值等同於 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。

// 接上demo
Reflect.ownKeys(obj).map(key => {
    console.log(key, obj[key])
})

/* 輸出結果:
name Scarlett
age 37
occupation actress
Symbol() "Johansson"
*/

 

以上,

關於對象的更多用法,請移步 Mozilla MDN

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM