JavaScript新手编写的99瓶啤酒歌词代码如何优化得更专业?
Hey there! Awesome work diving into JavaScript and building this classic 99 Bottles of Beer script—let's walk through some tweaks to make it cleaner, more maintainable, and aligned with modern JS best practices.
First, let's spot the key issues in your original code
- You're using
varwhich has function-level scope (instead of block-level), leading to unexpected variable hoisting and re-declarations (like redefiningbottleWordmultiple times in the same scope). - The loop has two
numberOfBottles--calls (one in the loop header, one inside the body) which skips numbers and breaks the lyric flow. - String concatenation with
+gets messy fast, especially with repeated text. - Duplicate logic for handling singular/plural bottle terms makes the code harder to update later.
Let's refactor step by step
1. Use modern variable declarations (let/const)
Swap var for let (for variables that change) and const (for values that never change). This avoids scope bugs and makes intent clearer:
// Good: const for fixed values, let for mutable counters const MAX_BOTTLES = 99; let numberOfBottles = MAX_BOTTLES;
2. Fix the loop logic
Remove the extra numberOfBottles-- inside the loop—your loop header already handles decrementing the counter each iteration.
3. Extract reusable logic into helper functions
Create a small function to handle the singular/plural bottle text (and edge cases like "No more bottles")—this follows the DRY (Don't Repeat Yourself) principle:
function getBottleLabel(count) { if (count === 0) return "No more bottles"; if (count === 1) return "1 bottle"; return `${count} bottles`; }
4. Use template literals for cleaner string formatting
Template literals (backticks `) let you embed variables directly into strings, making lyrics much easier to read:
// Instead of messy concatenation: console.log(`${currentLabel} of beer on the wall, ${currentLabel} of beer.`);
5. Structure verses into a dedicated function
Wrap each verse's output in a function to keep your main logic organized:
function printVerse(bottleCount) { const currentLabel = getBottleLabel(bottleCount); const nextLabel = getBottleLabel(bottleCount - 1); console.log(`${currentLabel} of beer on the wall, ${currentLabel} of beer.`); console.log(`Take one down and pass it around, ${nextLabel} of beer on the wall.\n`); }
Full Refactored Code
Here's the polished version putting it all together:
const MAX_BOTTLES = 99; function getBottleLabel(count) { if (count === 0) return "No more bottles"; if (count === 1) return "1 bottle"; return `${count} bottles`; } function printVerse(bottleCount) { const currentLabel = getBottleLabel(bottleCount); const nextLabel = getBottleLabel(bottleCount - 1); console.log(`${currentLabel} of beer on the wall, ${currentLabel} of beer.`); console.log(`Take one down and pass it around, ${nextLabel} of beer on the wall.\n`); } // Main loop to print all verses for (let numberOfBottles = MAX_BOTTLES; numberOfBottles > 0; numberOfBottles--) { printVerse(numberOfBottles); } // Final closing verses console.log("No more bottles of beer on the wall, no more bottles of beer."); console.log("Go to the store and buy some more, 99 bottles of beer on the wall.");
Why this is better
- Readability: Helper functions like
getBottleLabelandprintVersemake the code's purpose obvious at a glance. - Maintainability: If you ever want to tweak the lyric wording or bottle count, you only need to update one place (like the
MAX_BOTTLESconstant orgetBottleLabelfunction). - Modern JS Practices: Uses block-scoped variables and template literals, which are standard in professional JS code.
- Bug-Free: Fixes the double-decrement issue and eliminates variable hoisting surprises.
内容的提问来源于stack exchange,提问作者Fatima BT

