javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS获取对象自身属性

一文解析JS如何准确获取对象自身的属性

作者:LuckySusu

在 JavaScript 开发中,我们经常需要遍历对象的属性,本文将深入讲解如何准确获取对象非原型链上的属性(即“自身属性”),并结合你提供的代码,给出最佳实践,有需要的可以了解下

在 JavaScript 开发中,我们经常需要遍历对象的属性。但你是否遇到过这样的问题:

“为什么遍历一个简单对象时,会多出一些意想不到的方法?”

这是因为 for...in 循环会遍历对象自身 + 原型链上所有可枚举的属性。如果我们只想获取对象“自己”的属性,就必须使用 hasOwnProperty() 方法进行过滤。

本文将深入讲解如何准确获取对象非原型链上的属性(即“自身属性”),并结合你提供的代码,给出最佳实践。

一、问题背景:for...in的“陷阱”

看一个经典例子:

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)?

hasOwnProperty()的作用

person.hasOwnProperty('name');     // true  ← 自身属性
person.hasOwnProperty('sayHello'); // false ← 来自原型
person.hasOwnProperty('toString'); // false ← 来自 Object.prototype

四、更现代的替代方案

虽然 hasOwnProperty 非常经典,但现代 JavaScript 提供了更多选择:

方法1:Object.keys()—— 获取所有自身可枚举属性

const ownKeys = Object.keys(person);
console.log(ownKeys); // ['name']

// 结合 map 处理
const result = Object.keys(person).map(key => {
  return `${key}: ${person[key]}`;
});

优点:简洁,无需手动过滤;

缺点:只包含可枚举属性。

方法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: falseenumerable: 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的潜在风险与规避

风险:对象可能重写了hasOwnProperty

const badObj = {
  name: 'Test',
  hasOwnProperty: function () {
    return false; // 恶意重写
  }
};

badObj.hasOwnProperty('name'); // false ❌ 错误结果!

安全调用方式

使用 callObject.prototype.hasOwnProperty.call()

Object.prototype.hasOwnProperty.call(badObj, 'name'); // true ✅
// 或
{}.hasOwnProperty.call(badObj, 'name'); // true ✅

推荐在库或通用代码中使用这种写法,确保健壮性。

六、完整工具函数推荐

结合你提供的 iterate 函数,我们可以优化为更健壮的版本:

function getOwnProperties(obj) {
  const res = [];
  
  // 使用安全的 hasOwnProperty 调用
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      res.push(`${key}: ${obj[key]}`);
    }
  }
  
  return res;
}

// 或者使用现代 API
function getOwnPropertiesModern(obj) {
  return Object.keys(obj).map(key => `${key}: ${obj[key]}`);
}

七、总结:获取对象自身属性的方法对比

方法是否包含原型是否包含不可枚举是否包含 Symbol推荐场景
for...in + hasOwnProperty❌ 否❌ 否❌ 否兼容旧环境
Object.keys()❌ 否❌ 否❌ 否日常开发,简洁
Object.getOwnPropertyNames()❌ 否✅ 是❌ 否需要不可枚举属性
Reflect.ownKeys()❌ 否✅ 是✅ 是全面获取所有键

结语

“遍历对象时,for...in 是‘广撒网’,hasOwnProperty 是‘精准捕捞’。”

掌握如何区分自身属性继承属性,是写出高质量 JavaScript 代码的基本功。无论你是做数据处理、对象克隆,还是开发类库,这个知识点都至关重要。

记住:

到此这篇关于一文解析JS如何准确获取对象自身的属性的文章就介绍到这了,更多相关JS获取对象自身属性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文