getEmptyObject
Creates a truly empty object with no prototype chain. Returns a new object created with Object.create(null), which has no prototype chain and therefore no inherited properties or methods from Object.prototype. This creates the purest form of an empty object in JavaScript, ideal for use as a map or dictionary.
Signature
const getEmptyObject: <Value = any>() => Dictionary<Value>
Returns
A new empty object with null prototype
Examples
Basic usage and comparison with regular objects
import { getEmptyObject } from '@winglet/common-utils';
// Create a truly empty object
const empty = getEmptyObject();
console.log(empty); // {}
// No inherited properties
console.log(empty.toString); // undefined
console.log(empty.hasOwnProperty); // undefined
console.log(empty.constructor); // undefined
// Compare with regular empty object
const regular = {};
console.log(regular.toString); // [Function: toString]
console.log(regular.hasOwnProperty); // [Function: hasOwnProperty]
Using as a pure dictionary/map
// Create a clean dictionary without prototype pollution risks
const dict = getEmptyObject();
dict['user'] = 'John';
dict['admin'] = true;
dict['score'] = 95;
// No collision with Object.prototype properties
dict['toString'] = 'custom value'; // Safe to use
dict['constructor'] = 42; // No issues
dict['__proto__'] = 'data'; // Treated as regular property
console.log(dict['toString']); // 'custom value'
console.log(dict['constructor']); // 42
Creating a counter map
function countWords(text: string) {
const counts = getEmptyObject();
const words = text.toLowerCase().split(/\s+/);
for (const word of words) {
counts[word] = (counts[word] || 0) + 1;
}
return counts;
}
const wordCounts = countWords('The quick brown fox jumps over the lazy dog');
// No prototype methods interfering with word counting
Building a lookup table
// Create enum-like constants without prototype
const HttpStatus = getEmptyObject();
HttpStatus['OK'] = 200;
HttpStatus['NOT_FOUND'] = 404;
HttpStatus['SERVER_ERROR'] = 500;
// Use in checks
if (response.status === HttpStatus['NOT_FOUND']) {
handleNotFound();
}
// Iterate safely without prototype properties
for (const key in HttpStatus) {
console.log(`${key}: ${HttpStatus[key]}`);
// Only logs: OK: 200, NOT_FOUND: 404, SERVER_ERROR: 500
}
Secure configuration storage
// Store configuration without prototype pollution vulnerability
function createConfig() {
const config = getEmptyObject();
// Safe from prototype pollution attacks
config['__proto__'] = { malicious: 'code' }; // Just a regular property
config['constructor'] = { fake: 'constructor' }; // No override
return config;
}
const appConfig = createConfig();
console.log(Object.prototype.malicious); // undefined (not polluted)
Performance comparison for property checks
const nullProto = getEmptyObject();
const regular = {};
// Adding many properties
for (let i = 0; i < 10000; i++) {
nullProto[`prop${i}`] = i;
regular[`prop${i}`] = i;
}
// Iteration is faster without prototype chain
console.time('null prototype');
for (const key in nullProto) {
// No prototype chain to traverse
const value = nullProto[key];
}
console.timeEnd('null prototype'); // ~0.5ms
console.time('regular object');
for (const key in regular) {
if (regular.hasOwnProperty(key)) { // Need to check
const value = regular[key];
}
}
console.timeEnd('regular object'); // ~1.2ms
Playground
import { getEmptyObject } from '@winglet/common-utils'; // Create a truly empty object const empty = getEmptyObject(); console.log(empty); // {} // No inherited properties console.log(empty.toString); // undefined console.log(empty.hasOwnProperty); // undefined console.log(empty.constructor); // undefined // Compare with regular empty object const regular = {}; console.log(regular.toString); // [Function: toString] console.log(regular.hasOwnProperty); // [Function: hasOwnProperty]
Notes
Characteristics:
- No prototype chain (prototype is null)
- No inherited properties from Object.prototype
- Cannot use Object.prototype methods directly
- Faster property iteration (no prototype traversal)
- Immune to prototype pollution attacks
- Ideal for use as a pure dictionary/map
Advantages:
- Security: Prevents prototype pollution vulnerabilities
- Performance: Faster property iteration without prototype checks
- Clarity: No ambiguity about property ownership
- Safety: Can use any string as property name without conflicts
Limitations:
- Cannot use methods like toString(), hasOwnProperty() directly
- No constructor property
- typeof still returns 'object'
- instanceof Object returns false
Use Cases:
- Creating dictionaries or lookup tables
- Storing user input as object keys safely
- Building caches without prototype overhead
- Implementing enums or constant maps
- Security-critical property storage
- Performance-critical property iteration
Working with null prototype objects:
const obj = getEmptyObject();
// Use Object.prototype methods via call/apply
Object.prototype.toString.call(obj); // '[object Object]'
Object.prototype.hasOwnProperty.call(obj, 'key');
// Or use Object static methods
Object.keys(obj);
Object.values(obj);
Object.entries(obj);
Comparison with alternatives:
{}ornew Object(): Has full prototype chainMap: Better for non-string keys, has size propertyObject.create({}): Still has prototype chainObject.create(null): Equivalent to this function