nv-facutil-has
v1.0.5
Published
A comprehensive utility for checking and inspecting object properties and prototype chains in JavaScript.
Readme
has - JavaScript Property Inspector
A comprehensive utility for checking and inspecting object properties and prototype chains in JavaScript.
Installation
const has = require('nv-facutil-has');⚠️ Important Usage Note
The main function has() is designed for production use. All other utility functions are intended for CLI tools, testing frameworks, and debugging/inspection purposes only.
These inspection utilities provide deep introspection capabilities that are useful for:
- Interactive REPL/CLI environments
- Test assertions and debugging
- Object structure analysis
- Educational purposes
They are not recommended for production application logic due to performance considerations and complexity.
Main Function (Production Use)
has(object, key, only_own=false)
Checks if an object has a specific property.
Parameters:
object: The object to checkkey: The property key (string or symbol)only_own(default:false): Iftrue, checks only own properties; iffalse, includes prototype chain
Returns: boolean
Examples:
const obj = { a: 1, b: 2 };
// Check with prototype chain
has(obj, 'a'); // true
has(obj, 'toString'); // true (inherited from Object.prototype)
// Check only own properties
has(obj, 'a', true); // true
has(obj, 'toString', true); // false
// Safe with null/undefined
has(null, 'prop'); // false
has(undefined, 'prop'); // falseInspection Utilities (CLI/Testing Only)
slow(object, key, dig=Infinity)
Searches for a property within a specified depth range in the prototype chain.
Parameters:
object: The object to searchkey: The property key to finddig(default:Infinity): Maximum depth to search0: Own properties onlyn: Search up to n levels in prototype chainInfinity: Search entire chain
Returns: boolean
Examples:
const grandparent = { a: 1 };
const parent = Object.create(grandparent);
parent.b = 2;
const child = Object.create(parent);
child.c = 3;
has.slow(child, 'c', 0); // true (own property)
has.slow(child, 'b', 0); // false (not own)
has.slow(child, 'b', 1); // true (within 1 level)
has.slow(child, 'a', 2); // true (within 2 levels)
has.slow(child, 'a', 1); // false (need 2 levels)
has.slow(child, 'a', Infinity); // true (search all)exact(object, key, depth=Infinity)
Checks if a property exists at an exact depth in the prototype chain.
Parameters:
object: The object to checkkey: The property keydepth: Exact prototype chain depth0: Object's own propertyn: Property at exactly n levels upInfinity: Anywhere in chain
Returns: boolean
Examples:
const gp = { a: 1 };
const p = Object.create(gp);
p.b = 2;
const c = Object.create(p);
c.c = 3;
has.exact(c, 'c', 0); // true (own property)
has.exact(c, 'b', 0); // false (at level 1)
has.exact(c, 'b', 1); // true (exactly at level 1)
has.exact(c, 'a', 1); // false (at level 2, not 1)
has.exact(c, 'a', 2); // true (exactly at level 2)get_proto_chain(object)
Returns the complete prototype chain as an array.
Parameters:
object: The object to inspect
Returns: Array - Array of objects in the prototype chain
Examples:
const parent = { x: 1 };
const child = Object.create(parent);
child.y = 2;
const chain = has.get_proto_chain(child);
// [child, parent, Object.prototype]
console.log(chain.length); // 3
console.log(chain[0] === child); // true
console.log(chain[1] === parent); // trueget_prop_descs(object, split_layer=false)
Retrieves property descriptors from the prototype chain.
Parameters:
object: The object to inspectsplit_layer(default:false): Output formatfalse: Single object with all descriptors mergedtrue: Array of{object, descriptors}per layer
Returns: Object or Array
Examples:
const obj = { a: 1 };
Object.defineProperty(obj, 'b', {
value: 2,
writable: false,
enumerable: true
});
// Merged format (default)
const descs = has.get_prop_descs(obj, false);
console.log(descs.a);
// { value: 1, writable: true, enumerable: true, configurable: true }
console.log(descs.b.writable); // false
// Layer-by-layer format
const layers = has.get_prop_descs(obj, true);
layers.forEach((layer, i) => {
console.log(`Layer ${i}:`, Object.keys(layer.descriptors));
});get_all_keys(object, split_layer=false, enable_grouping=false)
Gets all property keys (including symbols and non-enumerable) from the prototype chain.
Parameters:
object: The object to inspectsplit_layer(default:false): Separate by prototype layersenable_grouping(default:false): Group by property characteristics
Returns: Array or Object
Property Signature Format (when enable_grouping=true):
k-__v-wec: string key, data property, writable+enumerable+configurablek-g__-_ec: string key, getter only, enumerable+configurablek-gs_-_e_: string key, getter+setter, enumerable onlyy-__v-wec: symbol key, data property, writable+enumerable+configurable
Format: {keyType}-{propType}-{flags}
- Key type:
k(string) ory(symbol) - Property type:
__v(data),g__(getter),_s_(setter),gs_(both) - Flags:
w(writable),e(enumerable),c(configurable),_(absent)
Examples:
const obj = { a: 1 };
Object.defineProperty(obj, 'getter', {
get: () => 'value',
enumerable: true
});
const sym = Symbol('test');
obj[sym] = 'symbol value';
// Simple list
const keys = has.get_all_keys(obj);
console.log(keys); // ['a', 'getter', Symbol(test)]
// Grouped by characteristics
const grouped = has.get_all_keys(obj, false, true);
console.log(grouped);
// {
// 'k-__v-wec': ['a'],
// 'k-g__-_ec': ['getter'],
// 'y-__v-wec': [Symbol(test)]
// }
// Split by layers
const parent = { x: 10 };
const child = Object.create(parent);
child.y = 20;
const layers = has.get_all_keys(child, true);
console.log(layers);
// [
// ['y'], // Layer 0: child's own
// ['x'] // Layer 1: parent's own
// ]nestify(object)
Converts a flat object into a nested prototype chain structure.
Parameters:
object: A flat object to convert
Returns: Object with properties distributed across prototype chain
How it works:
- First property → deepest prototype
- Middle properties → intermediate prototypes
- Last property → object's own property
Examples:
const flat = { a: 100, b: 200, c: 300 };
const nested = has.nestify(flat);
// Resulting structure:
// nested (own): { c: 300 }
// └─ prototype (empty layer)
// └─ prototype: { b: 200 }
// └─ prototype: { a: 100 }
console.log(nested.c); // 300 (own property)
console.log(nested.b); // 200 (from prototype)
console.log(nested.a); // 100 (from deeper prototype)
console.log(Object.hasOwn(nested, 'c')); // true
console.log(Object.hasOwn(nested, 'b')); // false
console.log(Object.hasOwn(nested, 'a')); // false
// Verify depths
has.exact(nested, 'c', 0); // true
has.exact(nested, 'b', 2); // true
has.exact(nested, 'a', 3); // trueflatify(object)
Converts a nested prototype chain back into a flat object.
Parameters:
object: Object with prototype chain to flatten
Returns: Flat object with all properties merged
Examples:
const nested = has.nestify({ a: 1, b: 2, c: 3 });
const flat = has.flatify(nested);
console.log(flat); // { c: 3, b: 2, a: 1 }
// All values preserved
console.log(flat.a === 1); // true
console.log(flat.b === 2); // true
console.log(flat.c === 3); // true
// Round-trip preservation
const original = { x: 10, y: 20, z: 30 };
const restored = has.flatify(has.nestify(original));
// restored contains all original properties and valuesUse Cases
Production Code
// Simple property existence check
if (has(config, 'database')) {
// Use config.database
}
// Check own properties only
if (has(userInput, 'password', true)) {
// Process password
}Testing & Debugging
// In a test framework
describe('Object structure', () => {
it('should have property at correct depth', () => {
const obj = createComplexObject();
assert(has.exact(obj, 'deepProp', 3));
});
it('should have all expected keys', () => {
const keys = has.get_all_keys(obj, false, true);
assert(keys['k-__v-wec'].includes('importantProp'));
});
});
// In CLI inspection tool
function inspect(obj) {
const chain = has.get_proto_chain(obj);
console.log(`Prototype chain depth: ${chain.length}`);
const descs = has.get_prop_descs(obj, true);
descs.forEach((layer, i) => {
console.log(`Level ${i}:`, Object.keys(layer.descriptors));
});
}Object Analysis
// Analyze object structure
function analyzeObject(obj) {
const allKeys = has.get_all_keys(obj, false, true);
console.log('Property distribution:');
for (const [sig, keys] of Object.entries(allKeys)) {
console.log(`${sig}: ${keys.length} properties`);
}
const layers = has.get_proto_chain(obj);
console.log(`\nPrototype depth: ${layers.length}`);
}Performance Considerations
Main function has():
- Optimized for production use
- O(1) for own properties
- O(n) for prototype chain (where n = chain depth)
Inspection utilities:
- May perform multiple traversals
- Use reflection APIs (getOwnPropertyDescriptors, etc.)
- Not optimized for high-frequency calls
- Best suited for development/debugging scenarios
API Summary
| Function | Purpose | Production Use |
|----------|---------|----------------|
| has(o, key, only_own) | Check property existence | ✅ Yes |
| slow(o, key, dig) | Search within depth range | ❌ No (CLI/Testing) |
| exact(o, key, depth) | Check exact depth | ❌ No (CLI/Testing) |
| get_proto_chain(o) | Get prototype chain | ❌ No (CLI/Testing) |
| get_prop_descs(o, split) | Get property descriptors | ❌ No (CLI/Testing) |
| get_all_keys(o, split, group) | Get all keys with details | ❌ No (CLI/Testing) |
| nestify(o) | Flatten to chain | ❌ No (CLI/Testing) |
| flatify(o) | Chain to flat | ❌ No (CLI/Testing) |
License
MIT
