how to enumerate/discover getters and setters in javascript? - javascript

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))

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.

You 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 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.

Related

How i can filter only true value from object and maintain the object structure

This is my current object which i get but i want to filter out only true values and also maintain the same structure in return.
Current Object =
errors :{
frontdesk: {
PreAudit: true,
AuthSent: false,
Limitation: false,
},
clinical: {
medicaid: true,
Vitals: true,
Height: false,
},
eligibilityVerification: {
Mentioned: true,
EVAttached: false,
}
}
i want like this =
errors :{
frontdesk: {
PreAudit: true,
},
clinical: {
medicaid: true,
Vitals: true,
},
eligibilityVerification: {
Mentioned: true,
}
}
To filter out only the true values in the object, you can use the Object.entries()
const filteredErrors = Object.entries(errors)
.filter(([key, value]) => value)
.reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {});
This will return a new object with the same structure as the original errors object, but with only the true values.

Getting specific properties of custom object

I have a CustomEvent object that I need to retrieve specific properties for. This object is not a plain object, but rather is the result of new CustomEvent();. When I output this object in the [Chrome] browser console, I see the following:
CustomEvent{
bubbles: false
cancelBubble: false
cancelable: false
composed: false
currentTarget: Window {...}
defaultPrevented: false
detail: {...}
eventPhase: 0
isTrusted: false
path: [Window]
returnValue: true
srcElement: Window {...}
target: Window {...}
timeStamp: 4979.4150000670925
type: "resize_element"
}
When I use Object.keys(custom_event_obj), I get only one key, isTrusted. This would mean that isTrusted is the only enumerable key.
I use the following code to make sure:
for(var key_str in custom_event_obj)
{
console.log(key_str, 'property is enumerable =', custom_event_obj.propertyIsEnumerable(key_str))
}
And I get the following result:
isTrusted is enumerable = true
detail is enumerable = false
initCustomEvent is enumerable = false
NONE is enumerable = false
CAPTURING_PHASE is enumerable = false
AT_TARGET is enumerable = false
BUBBLING_PHASE is enumerable = false
type is enumerable = false
target is enumerable = false
currentTarget is enumerable = false
eventPhase is enumerable = false
bubbles is enumerable = false
cancelable is enumerable = false
defaultPrevented is enumerable = false
composed is enumerable = false
timeStamp is enumerable = false
srcElement is enumerable = false
returnValue is enumerable = false
cancelBubble is enumerable = false
path is enumerable = false
composedPath is enumerable = false
stopPropagation is enumerable = false
stopImmediatePropagation is enumerable = false
preventDefault is enumerable = false
initEvent is enumerable = false
Object.getOwnPropertyNames gives me only one key as well: isTrusted.
This list contains keys that don't appear in the browser console result.
I'd like to get just the keys that appear in the browser console. How do I filter those keys out from the full list above?
Object.getOwnPropertyNames gives me only one key as well: isTrusted.
Not for me:
let CustomEvent = {
bubbles: false,
cancelBubble: false,
cancelable: false,
composed: false,
currentTarget: null,
defaultPrevented: false,
detail: null,
eventPhase: 0,
isTrusted: false,
path: [],
returnValue: true,
srcElement: null,
target: null,
timeStamp: 4979.4150000670925,
type: "resize_element"
}
console.log(Object.getOwnPropertyNames(CustomEvent));
But, while that does get you the property names, you'll still have to loop over the object and get the values for the properties.
You can also use .hasOwnProperty to only enumerate the properties that are not inherited.
let CustomEvent = {
bubbles: false,
cancelBubble: false,
cancelable: false,
composed: false,
currentTarget: null,
defaultPrevented: false,
detail: null,
eventPhase: 0,
isTrusted: false,
path: [],
returnValue: true,
srcElement: null,
target: null,
timeStamp: 4979.4150000670925,
type: "resize_element"
}
for(var prop in CustomEvent){
if(CustomEvent.hasOwnProperty(prop)){
console.log(prop, CustomEvent[prop]);
}
}

can I delete an attribute which configurable is false?

if I set an attribute with configurable: false, can I change or delete it any more? Just like below:
var a = {
test: {
// there are some function
}
}
Object.defineProperty(a, 'test', {configurable: false, value: null})
I want to do something like this a.test.b = '1'again, but now test is null and no-configurable.
Maybe this question is boring, but I just don't want to get something cannot be changed or used with js code.
I have try to redefined: Object.defineProperty(a, 'test', {configurable: true, value: {}})
or want to make a new 'test' with delete a.test
nothing worked.
Object.defineProperty(a, 'test', {configurable: false, value: null});
delete a.test; // error
a.test; // null, and I want it be {} with some code.
Object.defineProperty(a, 'test', {configurable: false, value: null});
// there is some code to make sure below code right.
a.test.b = 1
You can't delete the property, but if you use writable: true, you will be able to reassign it:
'use strict';
var a = {
test: {
b: 'x'
}
}
Object.defineProperty(a, 'test', {
configurable: false,
writable: true,
value: null
})
a.test = {
b: 'foo'
};
console.log(a.test.b);
(writable defaults to false, so you have to explicitly pass writable: true for the descriptor)
configurable: false means that the property descriptor can't be changed from a data descriptor to an accessor descriptor (or vice versa), nor can the property be removed from the object, but that doesn't prevent you from changing the actual value of the property, if the descriptor is writable.

"Property description must be an object" error

Using this code I have this issue:
$.fn.dxwShow = function (options)
{
console.log(typeof(options));
dxwShowSetOptions(options);
setInterval(function(){
dxwShowChange();
}, dxwShowOptions.time);
};
var dxwShowOptions = {
"transition" : "SlideToggle",
"time": 1000
};
var dxwShowStatus = {
current : 0
};
function dxwShowSetOptions(options)
{
console.dir(typeof(options));
dxwShowOptions = Object.create(dxwShowOptions, options);
}
function dxwShowChange()
{
console.log(dxwShowOptions);
};
$(function()
{
options = {
"time": 700,
"debug" : true
};
$("#dxwShow").dxwShow(options);
});
I want to update dxwShowOptions and so I use Object.create passing first the object I wanna copy and so the object containing the new parameters. Where is the mistake?
PS :Chrome say that the object is at the Object.create line.
Object.create takes a map of property descriptors. options is not such a list.
See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
If you wanted to still use Object.create, you'd need to modify options to be something more like
var options = {
time: {
enumerable: true,
configurable: true,
writable: true,
value: 700
},
debug: {
enumerable: true,
configurable: true,
writable: true,
value: true
}
};
But probably you want to use something more like _.extend.

How to change writable enumerable and configurable values of a Javascript object property?

From the node repl:
foo = { bar: 'baz'};
console.log (Object.getOwnPropertyDescriptor(foo, 'bar'))
Returned value:
{ value: 'baz',
writable: true,
enumerable: true,
configurable: true }
How do you change the writable enumerable, and configurable to false? What are these values called? Are they part of ES5.1? Are there more that the repl didn't output?
"How do you change the writable enumerable, and configurable to false?"
Object.defineProperty(foo, 'baz', {
enumerable:false,
writable:false,
configurable:false
});
There's also Object.defineProperties, which is the same, except you can set multiple properties, and Object.create, which let's you create a new object, and set its prototype object, and its descriptors.
"What are these values called?"
They're property descriptors.
"Are they part of ES5.1?"
Yes, ES5.
"Are there more that the repl didn't output?"
More what, property descriptors? No.
squint:I think there is like a little typing error in your answer.
Your code:
Object.defineProperty(foo, 'baz', {
enumerable:false,
writable:false,
configurable:false
});
but the second argument must be the name of the property and not the value, so the correct code is:
Object.defineProperty(foo, 'bar', {
enumerable:false,
writable:false,
configurable:false
});
Just wanted to add this in
You can change the attributes when first creating an object like so:
var newObj = Object.defineProperty({}, 'aPropertyName', {
enumerable:false,
writable:false,
configurable:false
});
You can also, you can alter multiple properties at once:
var newObj = Object.defineProperties({}, {
aPropertyName: {enumerable: false, writable: false, configurable: false},
anotherPropertyName: {enumerable: true, writable: true, configurable: false},
finalPropertyName: {enumerable: true, writable: false, configurable: true},
});
And of course passing in the object name with the previous method:
Object.defineProperties(objectName, {
aPropertyName: {enumerable: false, writable: false, configurable: false},
anotherPropertyName: {enumerable: true, writable: true, configurable: false},
finalPropertyName: {enumerable: true, writable: false, configurable: true},
});

Categories

Resources