在 JavaScript 中,属性的可枚举性是一个重要的概念。一个属性可以被定义为可枚举或不可枚举,这决定了它是否会出现在对象的迭代器中。通常情况下,我们可以使用 Object.keys()
或 for-in
循环来获取一个对象所有的可枚举属性。但是,如果一个属性是不可枚举的,并且是从父级对象继承而来的,那么该属性的名字是无法直接获取的。本文将探讨如何解决这个问题。
如何判断属性是否可枚举
首先,我们需要知道如何判断一个属性是否可枚举。在 ES5 中,可以使用 Object.getOwnPropertyDescriptor()
方法获取一个对象属性的描述符,并检查其中的 enumerable
属性。示例代码如下:
const obj = { foo: 'bar' }; const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo'); console.log(descriptor.enumerable); // true
ES6 引入了一个更加简洁的语法 —— 对象属性的简洁表示法,这种方法定义的属性默认是可枚举的。
const obj = { foo: 'bar' }; console.log(Object.getOwnPropertyDescriptor(obj, 'foo').enumerable); // true const obj2 = { ['baz']: 'qux' }; console.log(Object.getOwnPropertyDescriptor(obj2, 'baz').enumerable); // true
如何获取不可枚举的属性名
如果一个属性是从父级对象继承而来,并且不可枚举,那么我们无法直接通过 Object.keys()
或 for-in
循环获取它的名字。但是,我们可以使用一些工具方法来解决这个问题。
Object.getOwnPropertyNames()
Object.getOwnPropertyNames()
方法返回一个对象自身的所有属性名,包括不可枚举的属性。示例代码如下:
const obj = {}; Object.defineProperty(obj, 'foo', { value: 'bar', enumerable: false // 设置为不可枚举 }); console.log(Object.getOwnPropertyNames(obj)); // [ 'foo' ]
但是,Object.getOwnPropertyNames()
只返回自身的属性名,不能获取继承而来的属性名。
Reflect.ownKeys()
Reflect.ownKeys()
方法返回一个对象自身和继承的所有属性名,包括不可枚举的属性。示例代码如下:
const parent = { foo: 'bar' }; const child = Object.create(parent); // 创建一个继承自 parent 的空对象 Object.defineProperty(child, 'baz', { value: 'qux', enumerable: false // 设置为不可枚举 }); console.log(Reflect.ownKeys(child)); // [ 'baz', '__proto__' ]
注意,Reflect.ownKeys()
返回的数组中包含了 __proto__
属性,这是因为该方法获取的是自身和继承的所有属性名。
如何遍历所有属性名
如果我们想要获取一个对象所有的属性名,包括自身和继承的、可枚举和不可枚举的,可以使用以下方法:
-- -------------------- ---- ------- -------- ------------------------ - ----- ----- - --- --- ---------- - ---- -- - ------------------------------------------- ---------- - ---------------------------------- - ----- ----------- --- ------ ------ ------ - ----- ------ - - ---- ----- -- ----- ----- - ---------------------- ---------------------------- ------ - ------ ------ ----------- ----- -- ------- --- ---------------------------------------- -- - ------ ------------ ----- -
该方法使用了循环逐级获取父级原型链上的属性名,并将它们合并到一个数组中。
结论
在 JavaScript 中,如果一个属性是从
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/11987