最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何利用Object.getOwnPropertyNames获取实例自有键名并过滤掉内置原型干扰
时间:2026-06-13 09:46:52 编辑:袖梨 来源:一聚教程网
Object.getOwnPropertyNames只返回对象自身的所有自有属性键名(含不可枚举),不包含原型链上的任何属性。它天然绕过__proto__和原型链,无需过滤内置原型方法;真正需过滤的是实例自身可能存在的length、constructor等内置自有属性。
直接用 Object.getOwnPropertyNames 只能拿到实例自身的**所有**自有属性键名(包括不可枚举的),但它**不包含原型链上的属性**,所以本身就不会返回内置原型(如 Object.prototype、Array.prototype 等)的方法或属性。所谓“过滤掉内置原型干扰”,其实是对这个 API 的常见误解——它根本不会获取原型上的东西。
明确:getOwnPropertyNames 本来就不查原型
Object.getOwnPropertyNames(obj) 的作用范围严格限定在 obj 自身,即 obj.hasOwnProperty(key) === true 的那些键。它完全绕过 __proto__ 和整个原型链。例如:
(数组实例)
const arr = [1, 2];<br>console.log(Object.getOwnPropertyNames(arr)); // ['0', '1', 'length']<br>// 没有 push、map、toString 等 —— 它们在 Array.prototype 上,这里根本不会出现
真正需要过滤的,是构造函数/内置对象自动添加的自有属性
某些内置对象(如 new Date()、new RegExp()、或使用 Object.defineProperty 显式定义的不可枚举属性)会在实例上**自身拥有**一些非业务属性。这时才需按需过滤。常见策略:
- 排除 length、prototype、constructor 等典型静态键(尤其在处理类数组或自定义构造函数时)
-
跳过 Symbol 键(
getOwnPropertyNames不返回 Symbol,若需统一处理请改用Reflect.ownKeys) - 结合 hasOwnProperty + typeof 判断,比如只保留字符串键且值为普通数据类型
实用过滤示例:只留用户显式设置的字符串键
假设你有一个实例 user,想提取它“真正由代码赋值产生的自有键”(排除内置自动属性):
function getUserOwnDataKeys(obj) {<br> return Object.getOwnPropertyNames(obj)<br> .filter(key => {<br> // 排除 length、__*、constructor、prototype 等常见内置自有属性<br> if (key === 'length' || key === 'prototype' || key === 'constructor') return false;<br> if (key.startsWith('__')) return false;<br> // 可选:只保留值为 string/number/boolean/null 的键(排除函数、对象等)<br> const val = obj[key];<br> return ['string', 'number', 'boolean', 'undefined'].includes(typeof val) || val === null;<br> });<br>}<br><br>const user = { name: 'Alice', age: 30 };<br>Object.defineProperty(user, 'id', { value: 101, enumerable: false });<br>console.log(getUserOwnDataKeys(user)); // ['name', 'age', 'id']
注意:和 for...in、Object.keys 的关键区别
-
Object.keys(obj):只返回**可枚举**的自有属性键 -
for...in:遍历**可枚举**的自有 + 原型属性键(含Object.prototype) -
Object.getOwnPropertyNames(obj):返回**所有**自有属性键(无论是否可枚举),但**绝对不含原型链任何键**
因此,如果你看到结果里出现了 toString 或 hasOwnProperty,那说明该属性被手动定义在了实例自身(非常规操作),而不是“没过滤干净”。