admin管理员组文章数量:1194163
I am trying to discover the getters and setters on an object in typescript. I've tried Object.entries() and Object.keys() and neither of these return getters and setters. How can I enumerate these?
Edit: Here is some code that shows the problem:
class ThingWithGetter{
myProperty = 22;
get myGetter() {return 1;}
}
const thing = new ThingWithGetter()
// Does not show getter
console.log(Object.keys(thing));
// Does not show getter
const descriptors = Object.getOwnPropertyDescriptors(thing);
console.log(Object.keys(descriptors));
// Does not show getter
console.log(Object.entries(thing))
I am trying to discover the getters and setters on an object in typescript. I've tried Object.entries() and Object.keys() and neither of these return getters and setters. How can I enumerate these?
Edit: Here is some code that shows the problem:
class ThingWithGetter{
myProperty = 22;
get myGetter() {return 1;}
}
const thing = new ThingWithGetter()
// Does not show getter
console.log(Object.keys(thing));
// Does not show getter
const descriptors = Object.getOwnPropertyDescriptors(thing);
console.log(Object.keys(descriptors));
// Does not show getter
console.log(Object.entries(thing))
Share
Improve this question
edited Feb 25, 2020 at 18:14
Eric Jorgensen
asked Feb 25, 2020 at 17:20
Eric JorgensenEric Jorgensen
2,0522 gold badges15 silver badges25 bronze badges
3
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… – kaya3 Commented Feb 25, 2020 at 17:21
- @kaya3, that does not work for getters and setters – Eric Jorgensen Commented Feb 25, 2020 at 17:54
- That's because you defined the getter on the class, not the object. When I wrote the comment, your question said you wanted to discover them on the object. – kaya3 Commented Feb 25, 2020 at 18:03
5 Answers
Reset to default 10You can enumerate the getter name with this function:
function listGetters (instance) {
return Object.entries(
Object.getOwnPropertyDescriptors(
Reflect.getPrototypeOf(instance)
)
)
.filter(e => typeof e[1].get === 'function' && e[0] !== '__proto__')
.map(e => e[0]);
}
It will returns an array containing the getters names.
The reason this doesn't work is that the getter is on the class's prototype, which is on the instance's prototype chain, rather than on the instance itself.
To illustrate:
class A {
get x() { return 1 }
}
aInstance = new A()
// A {}
Object.getOwnPropertyDescriptors(aInstance)
// {}
Object.getOwnPropertyDescriptors(A.prototype)
// { constructor:
// { value: [Function: A],
// writable: true,
// enumerable: false,
// configurable: true },
// x:
// { get: [Function: get x],
// set: undefined,
// enumerable: false,
// configurable: true } }
Object.getOwnPropertyDescriptors(Object.getPrototypeOf(aInstance))
// { constructor:
// { value: [Function: A],
// writable: true,
// enumerable: false,
// configurable: true },
// x:
// { get: [Function: get x],
// set: undefined,
// enumerable: false,
// configurable: true } }
There a few good blog posts by Axel Rauschmayer on this topic:
- https://2ality.com/2011/06/prototypes-as-classes.html
- https://2ality.com/2012/11/property-assignment-prototype-chain.html
Note that if you are trying to enumerate all the properties, accessors, and methods on an object you will need to recursively walk the prototype chain until an object has a null
prototype.
The function Object.getOwnPropertyDescriptors
is in the ECMAScript latest draft specification, but is implemented in popular browsers. It returns the property descriptors belonging to an object.
Your use-case is a bit more difficult because the getter is defined on the class, not the object itself. So, you need to walk the prototype chain and build it that way. It's not enough to look at just the object's prototype, because the getter could be inherited from any superclass of the object's class.
Here's a recursive function which does it:
function getAllPropertyDescriptors(obj) {
if (!obj) {
return Object.create(null);
} else {
const proto = Object.getPrototypeOf(obj);
return {
...getAllPropertyDescriptors(proto),
...Object.getOwnPropertyDescriptors(obj)
};
}
}
The output for JSON.stringify(getAllPropertyDescriptors(thing))
is below. myGetter
is the third property descriptor; the actual output if you don't JSON.stringify it also includes references to the actual functions, so you can see if they have get
/set
properties.
{
"myProperty": {"value": 22, "writable": true, "enumerable": true, "configurable": true},
"constructor": {"writable": true, "enumerable": false, "configurable": true},
"myGetter": {"enumerable": false, "configurable": true},
"__defineGetter__": {"writable": true, "enumerable": false, "configurable": true},
"__defineSetter__": {"writable": true, "enumerable": false, "configurable": true},
"hasOwnProperty": {"writable": true, "enumerable": false, "configurable": true},
"__lookupGetter__": {"writable": true, "enumerable": false, "configurable": true},
"__lookupSetter__": {"writable": true, "enumerable": false, "configurable": true},
"isPrototypeOf": {"writable": true, "enumerable": false, "configurable": true},
"propertyIsEnumerable": {"writable": true, "enumerable": false, "configurable": true},
"toString": {"writable": true, "enumerable": false, "configurable": true},
"valueOf": {"writable": true, "enumerable": false, "configurable": true},
"__proto__": {"enumerable": false, "configurable": true},
"toLocaleString": {"writable": true, "enumerable": false, "configurable": true}
}
You could convert this into an iterative version, but that's probably unnecessary since most prototype chains are short, and the iterative version would need some wrangling to get overrides in the right order.
You can try something like:
var obj = {
get foo() {
return Math.random() > 0.5 ? 'foo' : 'bar';
}
};
Object.keys(obj).forEach(key => {
console.log("Getter:", Object.getOwnPropertyDescriptor(obj, key).get);
console.log("Setter: ", Object.getOwnPropertyDescriptor(obj, key).set);
})
Hope this works for you.
I had similar task, but I wanted to list only object's regular methods (without getters and setters). It ended up with implementation to list keys of any type you want:
//
// returns array of string: object's string properties (not include symbol properties)
//
// NOTE: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors
//
// flags:
// 0x1 -> only own (ignore prototype chain)
//
// 0x2 -> only enumerable (ignore non enumerable)
// 0x4 -> only non-enumerable
//
// 0x8 -> only writeable (ignore readonly values)
// 0x10 -> only readonly (ignore writeable values)
//
// 0x20 -> only configurable (ignore object property non-writable/deletable)
// 0x40 -> only non-configurable
//
// 0x80 -> ignore getters: class { get property() { ... } }
// 0x100 -> ignore setters: class { set property(v) { ... } }
// 0x200 -> ignore functions (ignore when propery value is regular function)
// 0x400 -> ignore undefined (ignore when property value is undefined)
// 0x800 -> ignore nulls (ignore when propery value is null)
// 0x1000 -> ignore regular values (ignore when property is regular value: non getter/setter/function/undefined/null)
//
Object.get_keys = function(obj, flags = 0) {
if (obj === undefined || obj == null) return []; // no properties...
const ret = new Set();
do {
for (const key of Object.getOwnPropertyNames(obj)) { // for each own key
const descriptor = Object.getOwnPropertyDescriptor(obj, key);
if (flags & 0x2) { if (!descriptor.enumerable) continue; } // if only enumerable
else if (flags & 0x4) { if (descriptor.enumerable) continue; } // if not enumerable
if (flags & 0x20) { if (!descriptor.configurable) continue; } // if only configurable
else if (flags & 0x40) { if (descriptor.configurable) continue; } // if non configurable
if ((flags & 0x80) != 0 && Object.hasOwn(descriptor, "get") && typeof(descriptor.get) == "function") continue; // if ignore getters
if ((flags & 0x100) != 0 && Object.hasOwn(descriptor, "set") && typeof(descriptor.set) == "function") continue; // if ignore setters
if (Object.hasOwn(descriptor, "value")) {
if (flags & 0x8) { if (!descriptor.writable) continue; } // if only writeable
else if (flags & 0x10) { if (descriptor.writable) continue; } // if only readonly
if (typeof(descriptor.value) == "function") { if (flags & 0x200) continue; }
else if (descriptor.value === undefined) { if (flags & 0x400) continue; }
else if (descriptor.value === null) { if (flags & 0x800) continue; }
else { if (flags & 0x1000) continue; }
}
ret.add(key);
}
if (flags & 1) break; // if 'only own' => break
obj = Object.getPrototypeOf(obj); // follow to internal object (from inheritance)
}
while (obj);
return Array.from(ret);
};
//
// returns array of string: only object's regular methods keys
//
Object.get_keys_methods = function(obj, flags = 0) {
return Object.get_keys(obj, (flags & 0x7F) | 0x1D80); // ignore: getters+setters+undefined+null+regular_values
};
Object.get_keys_accessors = function(obj, flags = 0) {
return Object.get_keys(obj, (flags & 0x7F) | 0x1E00); // ignore: functions+undefined+null+regular_values
};
In you case it is: get_key_accessors.
My current Chrome version gives:
Object.get_keys_methods(window) // returns: 994 keys (almost all are global constructors)
Object.get_keys_accessors(window) // returns: 184 keys
Object.get_keys_methods(document) // returns: 90 keys
Object.get_keys_accessors(document) // returns: 199 keys
本文标签: how to enumeratediscover getters and setters in javascriptStack Overflow
版权声明:本文标题:how to enumeratediscover getters and setters in javascript? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738496181a2089998.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论