一文解析JS如何準(zhǔn)確獲取對象自身的屬性
在 JavaScript 開發(fā)中,我們經(jīng)常需要遍歷對象的屬性。但你是否遇到過這樣的問題:
“為什么遍歷一個簡單對象時,會多出一些意想不到的方法?”
這是因為 for...in 循環(huán)會遍歷對象自身 + 原型鏈上所有可枚舉的屬性。如果我們只想獲取對象“自己”的屬性,就必須使用 hasOwnProperty() 方法進(jìn)行過濾。
本文將深入講解如何準(zhǔn)確獲取對象非原型鏈上的屬性(即“自身屬性”),并結(jié)合你提供的代碼,給出最佳實踐。
一、問題背景:for...in的“陷阱”
看一個經(jīng)典例子:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function () {
console.log(`Hello, I'm ${this.name}`);
};
const person = new Person('Alice');
// 直接使用 for...in
for (let key in person) {
console.log(key);
}
// 輸出:
// name
// sayHello ← 這是原型上的方法,但我們可能不想要它!
問題:sayHello 是從原型鏈繼承來的,并非 person 實例自身的屬性。
二、解決方案:使用hasOwnProperty()過濾
正確做法:使用 Object.prototype.hasOwnProperty() 方法判斷屬性是否屬于對象自身。
function iterate(obj) {
const res = [];
for (let key in obj) {
// ? 只保留對象自身的屬性
if (obj.hasOwnProperty(key)) {
res.push(key + ': ' + obj[key]);
}
}
return res;
}
const result = iterate(person);
console.log(result);
// 輸出: ["name: Alice"]
// ? 成功過濾掉了原型上的 sayHello
三、hasOwnProperty原理詳解
什么是“自身屬性”(Own Property)?
- 自身屬性:直接定義在對象實例上的屬性,如
this.name = 'Alice'; - 繼承屬性:通過原型鏈從父級繼承來的屬性或方法,如
sayHello。
hasOwnProperty()的作用
- 檢查某個屬性是否是對象的直接屬性;
- 返回
true表示該屬性是自身的; - 返回
false表示該屬性來自原型鏈或不存在。
person.hasOwnProperty('name'); // true ← 自身屬性
person.hasOwnProperty('sayHello'); // false ← 來自原型
person.hasOwnProperty('toString'); // false ← 來自 Object.prototype
四、更現(xiàn)代的替代方案
雖然 hasOwnProperty 非常經(jīng)典,但現(xiàn)代 JavaScript 提供了更多選擇:
方法1:Object.keys()—— 獲取所有自身可枚舉屬性
const ownKeys = Object.keys(person);
console.log(ownKeys); // ['name']
// 結(jié)合 map 處理
const result = Object.keys(person).map(key => {
return `${key}: ${person[key]}`;
});
優(yōu)點(diǎn):簡潔,無需手動過濾;
缺點(diǎn):只包含可枚舉屬性。
方法2:Object.getOwnPropertyNames()—— 包括不可枚舉屬性
// 添加一個不可枚舉屬性
Object.defineProperty(person, 'age', {
value: 25,
enumerable: false
});
console.log(Object.keys(person)); // ['name']
console.log(Object.getOwnPropertyNames(person)); // ['name', 'age']
適用場景:需要獲取 configurable: false 或 enumerable: false 的屬性。
方法3:Reflect.ownKeys()—— 最全的自身屬性列表
const obj = { a: 1 };
Object.defineProperty(obj, 'b', { value: 2, enumerable: false });
obj[Symbol('c')] = 3;
console.log(Reflect.ownKeys(obj)); // ['a', 'b', Symbol(c)]
包含:字符串鍵、Symbol 鍵、可枚舉和不可枚舉屬性。
五、hasOwnProperty的潛在風(fēng)險與規(guī)避
風(fēng)險:對象可能重寫了hasOwnProperty
const badObj = {
name: 'Test',
hasOwnProperty: function () {
return false; // 惡意重寫
}
};
badObj.hasOwnProperty('name'); // false ? 錯誤結(jié)果!
安全調(diào)用方式
使用 call 或 Object.prototype.hasOwnProperty.call():
Object.prototype.hasOwnProperty.call(badObj, 'name'); // true ?
// 或
{}.hasOwnProperty.call(badObj, 'name'); // true ?
推薦在庫或通用代碼中使用這種寫法,確保健壯性。
六、完整工具函數(shù)推薦
結(jié)合你提供的 iterate 函數(shù),我們可以優(yōu)化為更健壯的版本:
function getOwnProperties(obj) {
const res = [];
// 使用安全的 hasOwnProperty 調(diào)用
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
res.push(`${key}: ${obj[key]}`);
}
}
return res;
}
// 或者使用現(xiàn)代 API
function getOwnPropertiesModern(obj) {
return Object.keys(obj).map(key => `${key}: ${obj[key]}`);
}
七、總結(jié):獲取對象自身屬性的方法對比
| 方法 | 是否包含原型 | 是否包含不可枚舉 | 是否包含 Symbol | 推薦場景 |
|---|---|---|---|---|
| for...in + hasOwnProperty | ? 否 | ? 否 | ? 否 | 兼容舊環(huán)境 |
| Object.keys() | ? 否 | ? 否 | ? 否 | 日常開發(fā),簡潔 |
| Object.getOwnPropertyNames() | ? 否 | ? 是 | ? 否 | 需要不可枚舉屬性 |
| Reflect.ownKeys() | ? 否 | ? 是 | ? 是 | 全面獲取所有鍵 |
結(jié)語
“遍歷對象時,for...in 是‘廣撒網(wǎng)’,hasOwnProperty 是‘精準(zhǔn)捕撈’。”
掌握如何區(qū)分自身屬性與繼承屬性,是寫出高質(zhì)量 JavaScript 代碼的基本功。無論你是做數(shù)據(jù)處理、對象克隆,還是開發(fā)類庫,這個知識點(diǎn)都至關(guān)重要。
記?。?/strong>
- 用
hasOwnProperty過濾原型屬性; - 優(yōu)先使用
Object.keys()等現(xiàn)代 API; - 在通用代碼中使用
Object.prototype.hasOwnProperty.call()保證安全。
到此這篇關(guān)于一文解析JS如何準(zhǔn)確獲取對象自身的屬性的文章就介紹到這了,更多相關(guān)JS獲取對象自身屬性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
20分鐘輕松創(chuàng)建自己的Bootstrap站點(diǎn)
這篇文章主要教大家如何在短短的20分鐘內(nèi)輕松創(chuàng)建自己的Bootstrap站點(diǎn),學(xué)會使用twitter bootstrap建立一個站點(diǎn),從而鞏固Bootstrap一系列基礎(chǔ)知識,感興趣的小伙伴們可以參考一下2016-05-05
在JavaScript中如何將數(shù)字格式化為指定位數(shù)
本文介紹了在JavaScript中將數(shù)字格式化為3位,不足3位時在前面補(bǔ)0的幾種方法,每種方法結(jié)合實例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2025-11-11
JavaScript統(tǒng)計字符串中每個字符出現(xiàn)次數(shù)完整實例
這篇文章主要介紹了JavaScript統(tǒng)計字符串中每個字符出現(xiàn)次數(shù)的方法,以完整實例形式分析了JavaScript針對字符串中字符的遍歷操作相關(guān)技巧,需要的朋友可以參考下2016-01-01
微信JS-SDK坐標(biāo)位置如何轉(zhuǎn)換為百度地圖坐標(biāo)
這篇文章主要介紹了微信JS-SDK坐標(biāo)位置如何轉(zhuǎn)換為百度地圖坐標(biāo) 的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-07-07

