javascript
examples
examples.jsā”javascript
/**
* ============================================
* 3.9 NULLISH COALESCING - EXAMPLES
* ============================================
*/
// ============================================
// EXAMPLE 1: Basic Nullish Coalescing
// ============================================
console.log('--- Basic Nullish Coalescing ---');
// Returns default for null and undefined
console.log("null ?? 'default':", null ?? 'default'); // 'default'
console.log("undefined ?? 'default':", undefined ?? 'default'); // 'default'
// Returns the value for everything else (including falsy!)
console.log("0 ?? 'default':", 0 ?? 'default'); // 0
console.log("'' ?? 'default':", '' ?? 'default'); // ''
console.log("false ?? 'default':", false ?? 'default'); // false
console.log("NaN ?? 'default':", NaN ?? 'default'); // NaN
// ============================================
// EXAMPLE 2: ?? vs ||
// ============================================
console.log('\n--- ?? vs || ---');
const values = [null, undefined, 0, '', false, 'hello'];
console.log('Value\t\t\t|| result\t?? result');
console.log('ā'.repeat(50));
values.forEach((val) => {
const orResult = val || 'default';
const nullishResult = val ?? 'default';
const valStr = val === '' ? "''" : String(val);
console.log(`${valStr}\t\t\t${orResult}\t\t${nullishResult}`);
});
// ============================================
// EXAMPLE 3: The Problem with ||
// ============================================
console.log('\n--- The Problem with || ---');
// Setting volume to 0 should work!
const userVolume = 0;
const volumeWithOr = userVolume || 50;
const volumeWithNullish = userVolume ?? 50;
console.log('User set volume to 0');
console.log('Using || :', volumeWithOr); // 50 - WRONG!
console.log('Using ?? :', volumeWithNullish); // 0 - Correct!
// Empty string is intentional
const nickname = '';
const displayNameOr = nickname || 'Anonymous';
const displayNameNullish = nickname ?? 'Anonymous';
console.log('\nUser intentionally left nickname empty');
console.log('Using || :', displayNameOr); // 'Anonymous' - WRONG!
console.log('Using ?? :', displayNameNullish); // '' - Correct!
// ============================================
// EXAMPLE 4: Function Parameters
// ============================================
console.log('\n--- Function Parameters ---');
function createConfig(options) {
return {
port: options.port ?? 3000,
host: options.host ?? 'localhost',
timeout: options.timeout ?? 5000,
debug: options.debug ?? false,
retries: options.retries ?? 3,
};
}
// With some options
console.log('With custom port 0:', createConfig({ port: 0 }));
// port: 0 is preserved!
// With debug explicitly set to false
console.log('With debug false:', createConfig({ debug: false }));
// debug: false is preserved!
// ============================================
// EXAMPLE 5: API Response Handling
// ============================================
console.log('\n--- API Response Handling ---');
function processUser(userData) {
return {
name: userData.name ?? 'Unknown',
age: userData.age ?? 0,
bio: userData.bio ?? 'No bio available',
score: userData.score ?? 0,
isPremium: userData.isPremium ?? false,
};
}
// User with some null/undefined values
const apiResponse = {
name: 'John',
age: null, // Missing age
bio: '', // Empty bio intentionally
score: 0, // New user, 0 score
isPremium: false, // Free user
};
console.log('Processed user:', processUser(apiResponse));
// age: 0 (from default), bio: '' (preserved), score: 0 (preserved), isPremium: false (preserved)
// ============================================
// EXAMPLE 6: Chained Nullish Coalescing
// ============================================
console.log('\n--- Chained Nullish Coalescing ---');
const a = null;
const b = undefined;
const c = ''; // Empty string (falsy but not nullish)
const d = 0; // Zero (falsy but not nullish)
const e = 'final';
// Returns first non-nullish value
const result1 = a ?? b ?? c ?? d ?? e;
console.log('a ?? b ?? c ?? d ?? e:', result1); // '' (c is first non-nullish)
const result2 = a ?? b ?? d ?? e;
console.log('a ?? b ?? d ?? e:', result2); // 0 (d is first non-nullish)
// ============================================
// EXAMPLE 7: Nullish Assignment (??=)
// ============================================
console.log('\n--- Nullish Assignment (??=) ---');
const settings = {
theme: null,
fontSize: 0,
showHints: false,
};
console.log('Before assignment:', { ...settings });
// Only assigns if current value is null/undefined
settings.theme ??= 'light';
settings.fontSize ??= 14;
settings.showHints ??= true;
console.log('After ??= assignment:', settings);
// theme: 'light' (was null)
// fontSize: 0 (preserved - not nullish)
// showHints: false (preserved - not nullish)
// ============================================
// EXAMPLE 8: Lazy Initialization
// ============================================
console.log('\n--- Lazy Initialization ---');
class Database {
#connection = null;
getConnection() {
this.#connection ??= this.#createConnection();
return this.#connection;
}
#createConnection() {
console.log('Creating new connection...');
return { id: Math.random(), connected: true };
}
}
const db = new Database();
console.log('First call:', db.getConnection());
console.log('Second call:', db.getConnection()); // Reuses connection
// ============================================
// EXAMPLE 9: With Optional Chaining
// ============================================
console.log('\n--- With Optional Chaining ---');
const user = {
profile: {
settings: {
notifications: false,
volume: 0,
},
},
// name is missing
};
// Safe access with sensible defaults
const userName = user?.profile?.name ?? 'Anonymous';
const notifications = user?.profile?.settings?.notifications ?? true;
const volume = user?.profile?.settings?.volume ?? 50;
const theme = user?.profile?.settings?.theme ?? 'dark';
console.log('userName:', userName); // 'Anonymous'
console.log('notifications:', notifications); // false (preserved!)
console.log('volume:', volume); // 0 (preserved!)
console.log('theme:', theme); // 'dark' (default)
// ============================================
// EXAMPLE 10: Object Defaults
// ============================================
console.log('\n--- Object Defaults ---');
function mergeOptions(userOptions) {
const defaults = {
method: 'GET',
timeout: 5000,
cache: true,
retries: 3,
};
return {
method: userOptions?.method ?? defaults.method,
timeout: userOptions?.timeout ?? defaults.timeout,
cache: userOptions?.cache ?? defaults.cache,
retries: userOptions?.retries ?? defaults.retries,
};
}
console.log('Empty options:', mergeOptions({}));
console.log('With cache=false:', mergeOptions({ cache: false }));
console.log('With timeout=0:', mergeOptions({ timeout: 0 }));
console.log('Null input:', mergeOptions(null));
// ============================================
// EXAMPLE 11: Precedence with Parentheses
// ============================================
console.log('\n--- Precedence with Parentheses ---');
const value = null;
const backup = false;
const fallback = 'default';
// Must use parentheses when mixing with || or &&
const result3 = (value || backup) ?? fallback;
console.log("(null || false) ?? 'default':", result3); // 'default'
const result4 = value || (backup ?? fallback);
console.log("null || (false ?? 'default'):", result4); // false
// ============================================
// EXAMPLE 12: Real-World Scenarios
// ============================================
console.log('\n--- Real-World Scenarios ---');
// Form input handling
function processFormInput(input) {
return {
// For text: empty string is valid
username: input.username ?? '',
email: input.email ?? '',
// For numbers: 0 is valid
age: input.age ?? null,
quantity: input.quantity ?? 1,
// For booleans: false is valid
newsletter: input.newsletter ?? false,
terms: input.terms ?? false,
};
}
const formData = {
username: 'john',
email: '', // Empty but provided
age: 0, // Zero is valid
newsletter: false, // Explicitly unchecked
// quantity not provided
// terms not provided
};
console.log('Processed form:', processFormInput(formData));
// ============================================
// EXAMPLE 13: Default Function Arguments
// ============================================
console.log('\n--- Default Function Arguments ---');
// Using ?? inside the function vs default params
function greet(name, greeting) {
// ?? handles explicitly passed null/undefined
const safeName = name ?? 'Guest';
const safeGreeting = greeting ?? 'Hello';
return `${safeGreeting}, ${safeName}!`;
}
console.log('greet():', greet());
console.log("greet('John'):", greet('John'));
console.log("greet('John', 'Hi'):", greet('John', 'Hi'));
console.log('greet(null, null):', greet(null, null));
console.log("greet('', ''):", greet('', '')); // Preserves empty strings
console.log('\nā
All nullish coalescing examples completed!');