一文解析JS如何準(zhǔn)確獲取對(duì)象自身的屬性
在 JavaScript 開發(fā)中,我們經(jīng)常需要遍歷對(duì)象的屬性。但你是否遇到過(guò)這樣的問(wèn)題:
“為什么遍歷一個(gè)簡(jiǎn)單對(duì)象時(shí),會(huì)多出一些意想不到的方法?”
這是因?yàn)?for...in 循環(huán)會(huì)遍歷對(duì)象自身 + 原型鏈上所有可枚舉的屬性。如果我們只想獲取對(duì)象“自己”的屬性,就必須使用 hasOwnProperty() 方法進(jìn)行過(guò)濾。
本文將深入講解如何準(zhǔn)確獲取對(duì)象非原型鏈上的屬性(即“自身屬性”),并結(jié)合你提供的代碼,給出最佳實(shí)踐。
一、問(wèn)題背景:for...in的“陷阱”
看一個(gè)經(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 ← 這是原型上的方法,但我們可能不想要它!
問(wèn)題:sayHello 是從原型鏈繼承來(lái)的,并非 person 實(shí)例自身的屬性。
二、解決方案:使用hasOwnProperty()過(guò)濾
正確做法:使用 Object.prototype.hasOwnProperty() 方法判斷屬性是否屬于對(duì)象自身。
function iterate(obj) {
const res = [];
for (let key in obj) {
// ? 只保留對(duì)象自身的屬性
if (obj.hasOwnProperty(key)) {
res.push(key + ': ' + obj[key]);
}
}
return res;
}
const result = iterate(person);
console.log(result);
// 輸出: ["name: Alice"]
// ? 成功過(guò)濾掉了原型上的 sayHello
三、hasOwnProperty原理詳解
什么是“自身屬性”(Own Property)?
- 自身屬性:直接定義在對(duì)象實(shí)例上的屬性,如
this.name = 'Alice'; - 繼承屬性:通過(guò)原型鏈從父級(jí)繼承來(lái)的屬性或方法,如
sayHello。
hasOwnProperty()的作用
- 檢查某個(gè)屬性是否是對(duì)象的直接屬性;
- 返回
true表示該屬性是自身的; - 返回
false表示該屬性來(lái)自原型鏈或不存在。
person.hasOwnProperty('name'); // true ← 自身屬性
person.hasOwnProperty('sayHello'); // false ← 來(lái)自原型
person.hasOwnProperty('toString'); // false ← 來(lái)自 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):簡(jiǎn)潔,無(wú)需手動(dòng)過(guò)濾;
缺點(diǎn):只包含可枚舉屬性。
方法2:Object.getOwnPropertyNames()—— 包括不可枚舉屬性
// 添加一個(gè)不可枚舉屬性
Object.defineProperty(person, 'age', {
value: 25,
enumerable: false
});
console.log(Object.keys(person)); // ['name']
console.log(Object.getOwnPropertyNames(person)); // ['name', 'age']
適用場(chǎng)景:需要獲取 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)險(xiǎn)與規(guī)避
風(fēng)險(xiǎn):對(duì)象可能重寫了hasOwnProperty
const badObj = {
name: 'Test',
hasOwnProperty: function () {
return false; // 惡意重寫
}
};
badObj.hasOwnProperty('name'); // false ? 錯(cuò)誤結(jié)果!
安全調(diào)用方式
使用 call 或 Object.prototype.hasOwnProperty.call():
Object.prototype.hasOwnProperty.call(badObj, 'name'); // true ?
// 或
{}.hasOwnProperty.call(badObj, 'name'); // true ?
推薦在庫(kù)或通用代碼中使用這種寫法,確保健壯性。
六、完整工具函數(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é):獲取對(duì)象自身屬性的方法對(duì)比
| 方法 | 是否包含原型 | 是否包含不可枚舉 | 是否包含 Symbol | 推薦場(chǎng)景 |
|---|---|---|---|---|
| for...in + hasOwnProperty | ? 否 | ? 否 | ? 否 | 兼容舊環(huán)境 |
| Object.keys() | ? 否 | ? 否 | ? 否 | 日常開發(fā),簡(jiǎn)潔 |
| Object.getOwnPropertyNames() | ? 否 | ? 是 | ? 否 | 需要不可枚舉屬性 |
| Reflect.ownKeys() | ? 否 | ? 是 | ? 是 | 全面獲取所有鍵 |
結(jié)語(yǔ)
“遍歷對(duì)象時(shí),for...in 是‘廣撒網(wǎng)’,hasOwnProperty 是‘精準(zhǔn)捕撈’。”
掌握如何區(qū)分自身屬性與繼承屬性,是寫出高質(zhì)量 JavaScript 代碼的基本功。無(wú)論你是做數(shù)據(jù)處理、對(duì)象克隆,還是開發(fā)類庫(kù),這個(gè)知識(shí)點(diǎn)都至關(guān)重要。
記?。?/strong>
- 用
hasOwnProperty過(guò)濾原型屬性; - 優(yōu)先使用
Object.keys()等現(xiàn)代 API; - 在通用代碼中使用
Object.prototype.hasOwnProperty.call()保證安全。
到此這篇關(guān)于一文解析JS如何準(zhǔn)確獲取對(duì)象自身的屬性的文章就介紹到這了,更多相關(guān)JS獲取對(duì)象自身屬性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
通過(guò)JAVASCRIPT讀取ASP設(shè)定的COOKIE
通過(guò)JAVASCRIPT讀取ASP設(shè)定的COOKIE...2006-11-11
JS實(shí)現(xiàn)上下左右對(duì)稱的九九乘法表
九九乘法表使用很多種語(yǔ)言都可以實(shí)現(xiàn),本文給大家介紹js使用for、while循環(huán)來(lái)完成四種對(duì)稱的九九乘法表,對(duì)九九乘法表需要的朋友參考下2016-02-02
JavaScript接口的實(shí)現(xiàn)三種方式(推薦)
這篇文章主要介紹了JavaScript接口的實(shí)現(xiàn)三種方式,有注釋法,檢查屬性法和鴨式辨行法,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-06-06
js實(shí)現(xiàn)移動(dòng)端導(dǎo)航點(diǎn)擊自動(dòng)滑動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)移動(dòng)端導(dǎo)航點(diǎn)擊自動(dòng)滑動(dòng)效果,導(dǎo)航可左右滑動(dòng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
使用window.postMessage()方法在兩個(gè)網(wǎng)頁(yè)間傳遞數(shù)據(jù)
這篇文章介紹了使用window.postMessage()在兩個(gè)網(wǎng)頁(yè)間傳遞數(shù)據(jù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06

