JavaScriptでリフレクションを使用してオブジェクトのすべてのプロパティを取得するにはどうすればよいですか?
オブジェクトをループして、オブジェクトに属し、関数ではないすべてのキーを取得します。
var properties = [];
for(var key in obj) {
if(obj.hasOwnProperty(key) && typeof obj[key] !== 'function') {
properties.Push(key);
}
}
最近のブラウザでは、(列挙可能なプロパティだけでなく)すべてのプロパティ名を取得するには、Object.getOwnPropertyNames
..を使用します。
var props = Object.getOwnPropertyNames(my_object)
列挙可能なプロパティが必要ない場合は、Object.keys
..を使用します。
var props = Object.keys(my_object)
JavaScriptには、リフレクション(イントロスペクション)用の優れた組み込みツールがないため、手動で作成する必要があります。
まず、ここにソリューションのコードがあります
/**
* 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})`);
}
};
実際の例でこの関数を調べてください。
組み込みオブジェクト配列の場合
introspect(Array);
結果:
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 ()
実配列の場合(オブジェクト配列のインスタンス)
introspect([-10, '20', true, []]);
結果:
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 ()
実際のオブジェクトはどうですか?
introspect({
aa: 1,
bb: true,
cc: [],
dd: {},
c: (z, a= 2) => {},
b: function(z = 1, a=2) {},
d: function(b, zzz) {},
});
結果:
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)
この機能は、組み込みモジュールでもうまく機能します。モジュールMathを内省します。
introspect(Math);
結果
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 ()
どんな汚染が余分なコードに答えるかに関係なく、自分でやってみて結果を見てください
introspect(34.2313);
introspect(true);
introspect(Date);
introspect((new Date()));
introspect(String);
introspect('text');
完全なコードについては、関数「getFunctionParameters」(モジュール「functools.js」内)も使用しているので示します。
/**
* 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(' = ');
});
};
注:
弱くテストされた
それに関する良いリソース http://www.2ality.com/2011/01/reflection-and-meta-programming-in.html
ES6の機能を使用
var point = { x:5, y:8 };
for( var name in point ) {
// name contains the property name that you want
// point[name] contains the value
}