countObjectKey
Counts only the own enumerable properties of an object, excluding inherited properties. Iterates through all enumerable properties using a for-in loop but filters to count only properties that belong directly to the object, not inherited from the prototype chain. This provides the same count as Object.keys().length but with better performance by avoiding array creation.
Signature
const countObjectKey: <Type extends object>(object: Type) => number
Parameters
| Name | Type | Description |
|---|---|---|
object | - | The object whose own properties to count |
Returns
The count of own enumerable properties only
Examples
Basic usage with plain objects
import { countObjectKey } from '@winglet/common-utils';
// Plain object with own properties
const user = { name: 'Alice', age: 25, email: 'alice@example.com' };
console.log(countObjectKey(user)); // 3
// Empty object
console.log(countObjectKey({})); // 0
// Object with mixed key types
const mixed = {
str: 'value',
123: 'numeric',
[Symbol.for('sym')]: 'symbol' // Symbols are not counted
};
console.log(countObjectKey(mixed)); // 2 (symbols excluded)
Excluding inherited properties from prototype chain
// Object with inherited properties
const parent = { inherited1: 'value1', inherited2: 'value2' };
const child = Object.create(parent);
child.own1 = 'first';
child.own2 = 'second';
// countObjectKey counts only own properties
console.log(countObjectKey(child)); // 2
// Compare with countKey which includes inherited
import { countKey } from '@winglet/common-utils';
console.log(countKey(child)); // 4
// Same result as Object.keys().length
console.log(Object.keys(child).length); // 2
Working with constructor functions and prototypes
// Constructor with prototype methods
function Car(brand, model) {
this.brand = brand;
this.model = model;
}
Car.prototype.start = function() { console.log('Starting...'); };
Car.prototype.stop = function() { console.log('Stopping...'); };
const myCar = new Car('Toyota', 'Camry');
myCar.year = 2024;
// Only counts own properties, not prototype methods
console.log(countObjectKey(myCar)); // 3 (brand, model, year)
console.log(Object.keys(myCar)); // ['brand', 'model', 'year']
Performance optimization for large objects
// Large object with many properties
const largeData = {};
for (let i = 0; i < 100000; i++) {
largeData[`key_${i}`] = i;
}
// countObjectKey avoids array allocation
console.time('countObjectKey');
countObjectKey(largeData); // ~1ms
console.timeEnd('countObjectKey');
console.time('Object.keys.length');
Object.keys(largeData).length; // ~8ms (creates large array)
console.timeEnd('Object.keys.length');
// ~8x faster for large objects
Handling objects with null prototype
// Object without prototype chain
const nullProto = Object.create(null);
nullProto.prop1 = 'value1';
nullProto.prop2 = 'value2';
nullProto.prop3 = 'value3';
// Works correctly with null prototype objects
console.log(countObjectKey(nullProto)); // 3
// No Object.prototype methods available
console.log(nullProto.toString); // undefined
console.log(nullProto.hasOwnProperty); // undefined
Security-conscious property counting
// Potential prototype pollution scenario
const data = JSON.parse(untrustedInput);
// countObjectKey safely counts only own properties
const ownPropCount = countObjectKey(data);
// Safe validation
if (ownPropCount > MAX_ALLOWED_PROPERTIES) {
throw new Error('Too many properties');
}
// Process only own properties
for (const key in data) {
if (hasOwnProperty(data, key)) {
processProperty(key, data[key]);
}
}
Playground
import { countObjectKey } from '@winglet/common-utils'; // Plain object with own properties const user = { name: 'Alice', age: 25, email: 'alice@example.com' }; console.log(countObjectKey(user)); // 3 // Empty object console.log(countObjectKey({})); // 0 // Object with mixed key types const mixed = { str: 'value', 123: 'numeric', [Symbol.for('sym')]: 'symbol' // Symbols are not counted }; console.log(countObjectKey(mixed)); // 2 (symbols excluded)
Notes
Behavior Details:
- Counts ONLY own enumerable properties
- Uses hasOwnProperty check for each property
- Excludes inherited properties from prototype chain
- Excludes non-enumerable properties
- Excludes symbol properties
- Equivalent to Object.keys(obj).length in result
Performance Characteristics:
- Time Complexity: O(n) where n is total enumerable properties
- Space Complexity: O(1) constant space
- ~3-8x faster than Object.keys().length (varies by object size)
- No intermediate array allocation
- Slightly slower than countKey due to hasOwnProperty checks
Use Cases:
- Counting properties for validation or limits
- Security-sensitive contexts (avoiding prototype pollution)
- Performance-critical counting of own properties
- Compatibility with Object.keys() behavior
- Working with objects from untrusted sources
When to Use countKey Instead:
- Need to include inherited properties intentionally
- Working with objects designed to use prototype inheritance
- Maximum performance when prototype checking not needed
- Counting all enumerable properties is the goal
Implementation Note: Uses the hasOwnProperty utility which properly handles edge cases like objects with null prototype or overridden hasOwnProperty method.