Reputation: 64737
How to get all properties of an object using reflection in JavaScript?
Upvotes: 25
Views: 27301
Reputation: 4453
The JavaScript has no good, built-in tools for the reflection (introspection), so you need made it manually.
At first, here a code of a solution
/**
* Display details about an object at run-time
* @param {[any]} target Any object
* @return Nothing, all information will be display
*/
const introspect = (target) => {
// get type of a target
const typeTarget = typeof target;
// variable for type attribute of the target
let typeAttr;
// for properties and methods of the target
let properties = [];
let methods = [];
// if target is array, keep names all enumerable properties, simple put - numbers of indexes
// otherwise set to null
const enumerableProperties = Array.isArray(target) ? Object.keys(target) : null;
// determination functions and properties of the target by a parent object
Object.getOwnPropertyNames(Object.getPrototypeOf(target)).forEach((name) => {
if (typeof target[name] === 'function') {
methods.push(name);
} else if (target.hasOwnProperty(name) && properties.indexOf(name) === -1) {
properties.push(name);
}
});
// determination other functions and properties of the target
// filter it, if a name already added or if it is an array - filter all values of the indexes
Object.getOwnPropertyNames(target).forEach((name) => {
if (enumerableProperties !== null && enumerableProperties.indexOf(name) !== -1) {
return;
}
if (typeof target[name] === 'function') {
methods.push(name);
} else if (target.hasOwnProperty(name) && properties.indexOf(name) === -1) {
properties.push(name);
}
});
// order properties and methods by name in reverse
properties = properties.reverse();
methods = methods.reverse();
// display an obtained information by groups
console.log(`${typeTarget}: "${target}"`);
console.log(`\n\tProperties: ${properties.length}\n\t------------------`);
for (let i = properties.length - 1; i >= 0; i -= 1) {
typeAttr = typeof target[properties[i]];
console.log(`\t\t${properties[i]} --> ${typeAttr}`);
}
console.log(`\n\tMethods: ${methods.length}\n\t------------------`);
for (let i = methods.length - 1; i >= 0; i -= 1) {
let args = functools.getFunctionParameters(target[methods[i]]);
args = args.join(', ');
console.log(`\t\t${methods[i]} (${args})`);
}
};
Examine this function on real examples.
For built-in object Array
introspect(Array);
Result:
function: "function Array() { [native code] }"
Properties: 5
------------------
length --> number
name --> string
arguments --> object
caller --> object
prototype --> object
Methods: 8
------------------
apply ()
bind ()
call ()
toString ()
constructor ()
isArray ()
from ()
of ()
For real array (instance of object Array)
introspect([-10, '20', true, []]);
Result:
object: "-10,20,true,"
Properties: 1
------------------
length --> number
Methods: 29
------------------
constructor ()
toString ()
toLocaleString ()
join ()
pop ()
push ()
reverse ()
shift ()
unshift ()
slice ()
splice ()
sort ()
filter ()
forEach ()
some ()
every ()
map ()
indexOf ()
lastIndexOf ()
reduce ()
reduceRight ()
copyWithin ()
find ()
findIndex ()
fill ()
includes ()
entries ()
keys ()
concat ()
What about a real object?
introspect({
aa: 1,
bb: true,
cc: [],
dd: {},
c: (z, a= 2) => {},
b: function(z = 1, a=2) {},
d: function(b, zzz) {},
});
Result:
object: "[object Object]"
Properties: 4
------------------
aa --> number
bb --> boolean
cc --> object
dd --> object
Methods: 14
------------------
hasOwnProperty ()
constructor ()
toString ()
toLocaleString ()
valueOf ()
isPrototypeOf ()
propertyIsEnumerable ()
__defineGetter__ ()
__lookupGetter__ ()
__defineSetter__ ()
__lookupSetter__ ()
c (z, a = 2)
b (z = 1, a = 2)
d (b, zzz)
This function also good work with the built-in modules. Make introspect the module Math.
introspect(Math);
Result
object: "[object Math]"
Properties: 8
------------------
E --> number
LN10 --> number
LN2 --> number
LOG2E --> number
LOG10E --> number
PI --> number
SQRT1_2 --> number
SQRT2 --> number
Methods: 46
------------------
hasOwnProperty ()
constructor ()
toString ()
toLocaleString ()
valueOf ()
isPrototypeOf ()
propertyIsEnumerable ()
__defineGetter__ ()
__lookupGetter__ ()
__defineSetter__ ()
__lookupSetter__ ()
acos ()
asin ()
atan ()
ceil ()
clz32 ()
floor ()
fround ()
imul ()
max ()
min ()
round ()
sqrt ()
trunc ()
random ()
abs ()
exp ()
log ()
atan2 ()
pow ()
sign ()
asinh ()
acosh ()
atanh ()
hypot ()
cbrt ()
cos ()
sin ()
tan ()
sinh ()
cosh ()
tanh ()
log10 ()
log2 ()
log1p ()
expm1 ()
Matter what pollute answer superfluous code, try do it yourself and see results
introspect(34.2313);
introspect(true);
introspect(Date);
introspect((new Date()));
introspect(String);
introspect('text');
For full code, I also show the function "getFunctionParameters" (in module "functools.js"), since it used it.
/**
* Return array paraments of a function
* @param {[function]} func function
* @return {[array]} parameters the functions
*
*/
const getFunctionParameters = (func) => {
if (typeof func !== 'function') {
throw new Error('A argument is not function.');
}
const args = func.toString().match(/\((.*)\)/)[1];
return args.split(',').map((arg) => {
if (arg.indexOf('=') === -1) return arg.trim();
return arg
.split('=')
.map(val => val.trim())
.join(' = ');
});
};
Notes:
Weakly tested
Full code here https://github.com/setivolkylany/nodejs-utils
Good resource about it topic http://www.2ality.com/2011/01/reflection-and-meta-programming-in.html
Used the features of the ES6
Upvotes: 9
Reputation:
In modern browsers, to get all property names (not just enumerable properties), you'd use Object.getOwnPropertyNames
...
var props = Object.getOwnPropertyNames(my_object)
If you don't want enumerable properties, you'd use Object.keys
...
var props = Object.keys(my_object)
Upvotes: 23
Reputation: 10797
var point = { x:5, y:8 };
for( var name in point ) {
// name contains the property name that you want
// point[name] contains the value
}
Upvotes: 5
Reputation: 44205
Loop through the object and take every key that belongs to it and is not a function:
var properties = [];
for(var key in obj) {
if(obj.hasOwnProperty(key) && typeof obj[key] !== 'function') {
properties.push(key);
}
}
Upvotes: 30