在JavaScript中,有多种方式可以获取对象的所有方法和属性。以下是常用的几种方法:
- Object.keys()
获取对象自身的可枚举属性(不包括原型链上的属性)
const obj = {
name: 'John',
age: 30,
sayHello() {
console.log('Hello');
}
};
// 添加一个不可枚举属性
Object.defineProperty(obj, 'hiddenProp', {
value: 'hidden',
enumerable: false
});
console.log(Object.keys(obj)); // ['name', 'age', 'sayHello']
- Object.getOwnPropertyNames()
获取对象自身的所有属性(包括不可枚举属性,但不包括Symbol属性)
console.log(Object.getOwnPropertyNames(obj));
// ['name', 'age', 'sayHello', 'hiddenProp']
- Object.getOwnPropertySymbols()
获取对象自身的所有Symbol属性
const sym = Symbol('description');
obj[sym] = 'symbol value';
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(description)]
- Reflect.ownKeys()
获取对象自身的所有属性(包括字符串键、Symbol键,无论是否可枚举)
console.log(Reflect.ownKeys(obj));
// ['name', 'age', 'sayHello', 'hiddenProp', Symbol(description)]
- for...in 循环
遍历对象及其原型链上的可枚举属性
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log('Hello');
};
const person = new Person('John');
person.age = 30;
for (let key in person) {
console.log(key); // 'name', 'age', 'sayHello'
}
// 只获取自身属性
for (let key in person) {
if (person.hasOwnProperty(key)) {
console.log(key); // 'name', 'age'
}
}
- 区分方法和属性
function getAllMethods(obj) {
return Object.getOwnPropertyNames(obj)
.filter(key => {
return typeof obj[key] === 'function';
});
}
function getAllProperties(obj) {
return Object.getOwnPropertyNames(obj)
.filter(key => {
return typeof obj[key] !== 'function';
});
}
const example = {
name: 'Test',
value: 100,
method1() {},
method2() {}
};
console.log('Methods:', getAllMethods(example)); // ['method1', 'method2']
console.log('Properties:', getAllProperties(example)); // ['name', 'value']
- 获取包括原型链上的所有方法
function getAllMethodsIncludingPrototype(obj) {
const methods = new Set();
// 遍历当前对象及其原型链
let current = obj;
while (current && current !== Object.prototype) {
Object.getOwnPropertyNames(current)
.filter(key => typeof current[key] === 'function')
.forEach(method => methods.add(method));
current = Object.getPrototypeOf(current);
}
return Array.from(methods);
}
class Parent {
parentMethod() {}
}
class Child extends Parent {
childMethod() {}
}
const instance = new Child();
console.log(getAllMethodsIncludingPrototype(instance));
// ['childMethod', 'parentMethod']
- 完整的工具函数
function inspectObject(obj) {
console.log('=== 对象检查 ===');
console.log('Object.keys():', Object.keys(obj));
console.log('Object.getOwnPropertyNames():', Object.getOwnPropertyNames(obj));
console.log('Object.getOwnPropertySymbols():', Object.getOwnPropertySymbols(obj));
console.log('Reflect.ownKeys():', Reflect.ownKeys(obj));
console.log('\n=== 方法列表 ===');
const methods = Object.getOwnPropertyNames(obj)
.filter(key => typeof obj[key] === 'function');
console.log('Methods:', methods);
console.log('\n=== 属性列表 ===');
const properties = Object.getOwnPropertyNames(obj)
.filter(key => typeof obj[key] !== 'function');
console.log('Properties:', properties);
}
// 使用示例
const testObj = {
prop1: 'value1',
prop2: 123,
method1() {},
method2() {}
};
inspectObject(testObj);
注意事项
- 可枚举性:Object.keys() 和 for...in 只返回可枚举属性
- 原型链:for...in 会遍历原型链,其他方法只返回自身属性
- Symbol属性:需要使用专门的方法来获取
- 性能考虑:在性能敏感的场景中,避免频繁使用这些反射方法
根据你的具体需求选择合适的方法来获取对象的属性和方法。