lively.lang_properties.js
/**
* Methods to streamline the querying of object properties.
* @module lively.lang/properties
*/
function all (object, predicate) {
// ignore-in-doc
const a = [];
for (const name in object) {
if ((object.__lookupGetter__(name) || typeof object[name] !== 'function') &&
(predicate ? predicate(name, object) : true)) { a.push(name); }
}
return a;
}
/**
* For a given object, traverses all prototypes in the proto chain
* and collects all property descriptors and merges them into one object.
* @param { Object } obj - The object to collect the property descriptors for.
* @returns { Object } The collection of property descriptors as a dictionary.
*/
function allPropertyDescriptors (obj) {
let proto = obj;
const descriptors = {};
while (proto = proto.__proto__) {
// fixme: maybe the performance is not ideal
Object.assign(descriptors, Object.getOwnPropertyDescriptors(proto));
}
return descriptors;
}
function getPropertyDescriptor (obj, prop) {
let proto = obj;
let descriptor;
while (proto = proto.__proto__) {
descriptor = Object.getOwnPropertyDescriptor(obj, prop);
if (descriptor) break;
}
return descriptor;
}
/**
* For a given object only returns all the *property or function names*
* that are directly defined on the object itself. Here we *do not* consider
* what is defined on any of the prototypes in the prototype chain of the given object.
* If `predicate` is given, these can further be filtered by a custom condition.
* @param { Object } obj - The object to collect the property and function names for.
* @param { function(*, string): boolean } [predicate] - The predicate to filter the properties by further.
* @returns { string[] } The names of all the local properties or functions.
*/
function allOwnPropertiesOrFunctions (obj, predicate) {
return Object.getOwnPropertyNames(obj).reduce(function (result, name) {
if (predicate ? predicate(obj, name) : true) result.push(name);
return result;
}, []);
}
/**
* For a given object only returns all the *property names*
* that are directly defined on the object itself. Here we *do not* consider
* what is defined on any of the prototypes in the prototype chain of the given object.
* @param { Object } object- The object to collect the property names for.
* @returns { string[] } The names of all the local properties.
*/
function own (object) {
const a = [];
for (const name in object) {
if (object.hasOwnProperty(name) && (object.__lookupGetter__(name) ||
object[name] !== 'function')) { a.push(name); }
}
return a;
}
/**
* For a given object iterate over its local properties
* invoking `func` on each time.
* @param { Object } object - The object whose properties to traverse.
* @param { function(string, *): * } func - The iteration function.
* @param { Object } [context] - The binding of `this` during the execution of `func`.
* @returns { any[] } The results of each iteration.
*/
function forEachOwn (object, func, context) {
const result = [];
for (const name in object) {
if (!object.hasOwnProperty(name)) continue;
const value = object[name];
if (value !== 'function') {
result.push(func.call(context || this, name, value));
}
}
return result;
}
/**
* For a given `object` return the name of the property that is equal to `value`.
* @param { Object } object - The object whose properties to check.
* @param { * } value - The value to scan the properties for.
* @returns { string } The name of the property that stores the same `value`.
*/
function nameFor (object, value) {
for (const name in object) {
if (object[name] === value) { return name; }
}
return undefined;
}
/**
* Traverse all the values of a given object, including the ones defined in the prototype chain.
* @param { Object } obj - The object to gather all the values from.
* @returns { any[] } The list of all values.
*/
function values (obj) {
const values = [];
for (const name in obj) { values.push(obj[name]); }
return values;
}
/**
* Traverse all the values of a given object, only considering the ones directly defined on the object itself.
* @param { Object } obj - The object to gather all the local values from.
* @returns { any[] } The list of all (own) values.
*/
function ownValues (obj) {
const values = [];
for (const name in obj) {
if (obj.hasOwnProperty(name)) { values.push(obj[name]); }
}
return values;
}
/**
* For a given `obj` and `predicate` checks wether any property defined for `obj` satisfies the condition
* defined by `predicate`.
* @param { Object } obj - The object whose properties to check.
* @param { function(Object, string): boolean } predicate - The predicate to check the properties for.
* @returns { boolean } Wether or not any of the properties of the object satisfies the predicate.
*/
function any (obj, predicate) {
for (const name in obj) {
if (predicate(obj, name)) { return true; }
}
return false;
}
/**
* Gather all the property names of a given 'obj'. Can be further filtered by specifying a `predicate`.
* @param { Object } obj - The object whose properties to collect.
* @param { function(Object, string): boolean } [predicate] - The predicate to filter the properties with.
* @return { string[] } The list of all the names of the matching properties.
*/
function allProperties (obj, predicate) {
const result = [];
for (const name in obj) {
if (predicate ? predicate(obj, name) : true) { result.push(name); }
}
return result;
}
/**
* Uses the property names of `obj` to generate a hash value.
* @param { Object } obj - The object to generate a hash for.
* @returns { string } The computed hash.
*/
function hash (obj) {
return Object.keys(obj).sort().join('').hashCode();
}
export {
all,
allOwnPropertiesOrFunctions,
allPropertyDescriptors,
own,
forEachOwn,
nameFor,
values,
ownValues,
any,
allProperties,
hash
};