我正在编写一些代码来扩展Object
,并且我想遍历对象内的方法。当我输出this.constructor
的值时,我看到了我想要的方法(在下面的示例中,我看到了test
)。但是,当我使用for遍历方法时,它仅显示方法getType
。我该如何获取class A
的方法?
Object.prototype.getType = function () {
// Outputs correct class and methods
console.log(this.constructor)
for (let i in this.constructor) {
// Outputs wrong methods
console.log(i)
}
}
class A {
test() {console.log('hello')}
}
new A().getType()
答案 0 :(得分:2)
两个问题:
属性可以枚举– for ...在循环中访问–或不可以。在class
中定义方法时,默认值是不可枚举的。 (另一方面,Object.prototype.getType
可以枚举,因为这是通过赋值创建属性时的默认值。)
您正在遍历该对象声称为其构造函数的属性,但是诸如test
之类的非静态方法是该构造函数的prototype
属性(A.prototype
)的属性,而不是构造函数本身(A.test
不是东西)。
您可以使用Object.getOwnPropertyNames
函数找到不可枚举的属性:
Object.prototype.getType = function () {
for (let name of Object.getOwnPropertyNames(this.constructor.prototype)) {
console.log(name)
}
}
请注意,这仅包括自己的属性 –直接在对象上的属性–因此,如果要包括继承的方法,则必须向上访问原型链。
function* getAllPropertyNames(obj) {
do {
yield* Object.getOwnPropertyNames(obj)
} while (obj = Object.getPrototypeOf(obj))
}
Object.prototype.getType = function () {
for (let name of getAllPropertyNames(this.constructor.prototype)) {
console.log(name)
}
}
如果您想直接在对象上包含属性,则必须从那里开始(并希望this.constructor.prototype
是Object.getPrototypeOf(this)
)。
Object.prototype.getType = function () {
for (let name of getAllPropertyNames(this)) {
console.log(name)
}
}
此外,请勿扩展Object.prototype
。 尤其是没有可枚举的属性。当您执行此操作时,管理层对以神秘方式破坏的依赖关系不承担任何责任。
答案 1 :(得分:1)
也许不是最优雅的解决方案,但是一种实现方法是通过调用Object.getOwnPropertyNames()
,并传递对象实例__proto__
引用。
Object.prototype.getType = function () {
/*
// Outputs correct class and methods
console.log(this.constructor)
for (let i in this.constructor) {
// Outputs wrong methods
console.log(i)
}
*/
for(let j of Object.getOwnPropertyNames(this.__proto__)
.filter(method => method !== 'constructor'))
{
// Outputs properties of prototype, without constructor method
console.log(j);
}
}
class A {
test() {console.log('hello')}
}
new A().getType()
答案 2 :(得分:1)
getType 名称似乎不合适,您要查找的是属性,因此 getAllProperties 似乎是一个更好的名称。
正如其他人所说,出于多种原因,您需要进入[[Prototype]]
链:
[[Prototype]]
链以 null 结尾,它是Object.prototype的原型,并且是所有原型层次结构的顶部。该函数还应删除每个原型上可能出现的重复项(例如 constructor 和 length 很常见)。
function getAllProperties(obj) {
// Recursively get properties up [[Prototype]] chain
function loop(obj) {
let props = Object.getOwnPropertyNames(obj);
let proto = Object.getPrototypeOf(obj);
// Stop at null
if (proto !== null) {
return props.concat(loop(proto));
}
return props;
}
let allProps = loop(obj);
// Remove duplicates
return allProps.filter((prop, i) => !allProps.includes(prop, i+1));
}
console.log(getAllProperties('a'))
如果只需要方法,则在进行typeof x == 'function'
过滤时使用:
function getAllMethods(obj) {
// Recursively get properties up [[Prototype]] chain
function loop(obj) {
// Get all properties, filter for functions
let props = Object.getOwnPropertyNames(obj).filter((prop, i, props) => typeof props[prop] == 'function');
let proto = Object.getPrototypeOf(obj);
// Stop at null
if (proto !== null) {
return props.concat(loop(proto));
}
return props;
}
let allMethods = loop(obj);
// Remove duplicates
return allMethods.filter((prop, i) => !allMethods.includes(prop, i + 1));
}
console.log(getAllMethods('a'))