10 Examples Where ASF's Object Methods Are Simply Better
let config = {
darkMode: true, notifications: false,
autoSave: true, analytics: false
};
let enabled = config.filter(fun(val) {
return val == true;
});
const config = {
darkMode: true, notifications: false,
autoSave: true, analytics: false
};
const enabled = Object.fromEntries(
Object.entries(config)
.filter(([key, val]) => val === true)
);
// Must remember to destructure [key, val]
// Must remember Object.fromEntries at the end
let prices = {
laptop: 1200,
mouse: 25,
keyboard: 75
};
// Apply 20% discount to everything
let sale = prices.map(fun(price) {
return price * 0.8;
});
const prices = {
laptop: 1200,
mouse: 25,
keyboard: 75
};
// Remember: must return [key, value] pairs!
const sale = Object.fromEntries(
Object.entries(prices)
.map(([key, price]) => [key, price * 0.8])
);
// Forgot to preserve key? Broken.
// Forgot fromEntries? You get an array.
let user = {
username: 'alice',
email: 'alice@example.com',
age: 25
};
// Check all fields present and valid
let valid = user.every(fun(val, key) {
return val != null && val != '';
});
// Can also validate by key name!
let hasRequired = user.every(fun(val, key) {
return key == 'age' || typeof val == 'string';
});
const user = {
username: 'alice',
email: 'alice@example.com',
age: 25
};
// Loses key information!
const valid = Object.values(user)
.every(val => val != null && val !== '');
// Need entries for key access
const hasRequired = Object.entries(user)
.every(([key, val]) =>
key === 'age' || typeof val === 'string'
);
// Choose: lose keys or use verbose syntax?
let features = {
darkMode: false,
analytics: false,
logging: true,
debugging: true
};
// Any feature starting with 'log' enabled?
let hasLogging = features.some(fun(val, key) {
return val && key.startsWith('log');
});
// Any feature enabled at all?
let anyEnabled = features.some(fun(val) {
return val == true;
});
const features = {
darkMode: false,
analytics: false,
logging: true,
debugging: true
};
// Need that [key, val] destructuring again...
const hasLogging = Object.entries(features)
.some(([key, val]) =>
val && key.startsWith('log')
);
// At least this one's simpler
const anyEnabled = Object.values(features)
.some(val => val === true);
// Different patterns for different needs
let scores = {
math: 85,
english: 92,
science: 78
};
// Process each property
scores.forEach(fun(val, key) {
print(key + ': ' + val);
});
// Works just like array.forEach()
// Get value, key, and even the object itself!
const scores = {
math: 85,
english: 92,
science: 78
};
// No scores.forEach() - objects aren't iterable
// Must convert to array first
Object.entries(scores).forEach(([key, val]) => {
console.log(key + ': ' + val);
});
// Or use for...in (but that has prototype issues)
// Or use Object.keys() then loop...
// Multiple ways, none direct
let defaults = {
timeout: 30,
retry: 3,
verbose: false
};
let userConfig = {
timeout: 60,
cache: true
};
defaults.merge(userConfig);
// Result:
// { timeout: 60, retry: 3, verbose: false, cache: true }
const defaults = {
timeout: 30,
retry: 3,
verbose: false
};
const userConfig = {
timeout: 60,
cache: true
};
Object.assign(defaults, userConfig);
// or: const merged = { ...defaults, ...userConfig };
// Result:
// { timeout: 60, retry: 3, verbose: false, cache: true }
let config = { a: 1, b: 2, c: 3 };
let count = config.size(); // 3
let empty = config.isEmpty(); // false
config.clear();
empty = config.isEmpty(); // true
// Readable, discoverable, obvious
// Works like .length for arrays
const config = { a: 1, b: 2, c: 3 };
const count = Object.keys(config).length;
const empty = Object.keys(config).length === 0;
// Or with newer syntax
const empty2 = Object.keys(config).length === 0;
// Always: convert to array → get length
// Every. Single. Time.
// No .isEmpty(), must compare === 0
let products = {
p1: { name: 'Widget', cost: 10, stock: 15 },
p2: { name: 'Gadget', cost: 25, stock: 0 },
p3: { name: 'Tool', cost: 30, stock: 8 }
};
let result = products
.filter(fun(item) {
return item.stock > 0;
})
.map(fun(item) {
return { name: item.name, price: item.cost * 1.5 };
})
.filter(fun(item) {
return item.price > 30;
});
// Clean pipeline. Object → Object → Object
// No type conversions!
const products = {
p1: { name: 'Widget', cost: 10, stock: 15 },
p2: { name: 'Gadget', cost: 25, stock: 0 },
p3: { name: 'Tool', cost: 30, stock: 8 }
};
const result = Object.fromEntries( // Array → Object
Object.entries( // Object → Array
Object.fromEntries( // Array → Object
Object.entries(products) // Object → Array
.filter(([k, item]) => item.stock > 0)
.map(([k, item]) => [k, {
name: item.name,
price: item.cost * 1.5
}])
)
).filter(([k, item]) => item.price > 30)
);
// Nested conversions. Hard to read. Easy to mess up.
let user = {
name: 'John',
scores: [85, 90],
address: { city: 'Boston' }
};
let copy = user.clone();
// Modify copy
copy.name = 'Jane';
copy.scores[1] = 95;
copy.address.city = 'NYC';
// Original untouched!
// user.name = 'John'
// user.address.city = 'Boston'
const user = {
name: 'John',
scores: [85, 90],
address: { city: 'Boston' }
};
// Option 1: Modern but new (2022+)
const copy1 = structuredClone(user);
// Option 2: JSON trick (breaks with functions, dates, etc)
const copy2 = JSON.parse(JSON.stringify(user));
// Option 3: Spread (SHALLOW only!)
const copy3 = { ...user };
copy3.address.city = 'NYC';
// OOPS! user.address.city is now 'NYC' too!
// No simple, universal solution
let config = {
timeout: 30,
retry: 3
};
// Property exists → return its value
let timeout = config.get('timeout', 60); // 30
// Property missing → return default
let port = config.get('port', 8080); // 8080
// Clean, safe, readable
// No ?? or || operators needed
const config = {
timeout: 30,
retry: 3
};
// Nullish coalescing (newer, better)
let port = config.port ?? 8080;
// Logical OR (watch out for 0 and '')
let port2 = config.port || 8080;
// Manual check (verbose)
let port3 = config.port !== undefined
? config.port : 8080;
// ?? vs || behave differently!
// 0, '', false with || → use default
// Only null/undefined with ?? → use default