JS中while循环放入函数后结果差异原因及代码精简方法
运行结果差异原因
核心原因是JavaScript中var关键字的作用域规则与变量提升特性:
var声明的变量没有块级作用域,仅在全局作用域、函数作用域内生效- 所有
var声明都会被提升到所属作用域的最顶部,声明后默认赋值为undefined,直到代码执行到赋值位置才会更新值
两段代码的差异点具体如下:
- 第一段代码的循环写在独立的普通代码块
{}中,这个块不会创建新的作用域,块内所有var word声明都会被提升到全局作用域,和块外定义的var word = "bottles"是同一个全局变量,初始值就是预设的"bottles",运行时不会出现值异常。 - 第二段代码的循环封装在函数内部,函数会创建独立的函数作用域,函数内所有
var word声明都会被提升到myName函数的作用域顶部,此时函数内部的word是独立的局部变量,会遮蔽外层全局的word。函数刚执行时内部word值为undefined,直到第一次触发count === 1的判断分支才会被赋值为"bottle",之前循环中打印word都会得到undefined,最终运行结果和第一段产生明显差异。
代码优化建议
原代码存在重复声明变量、重复写单复数判断、字符串拼接冗余、分支嵌套过深的问题,可以按以下思路优化:
- 用
let/const替代var,从根源上避免变量提升、作用域遮蔽导致的异常,let/const自带块级作用域,语义更清晰 - 把单复数判断逻辑抽离,不要在多个分支重复写相同的判断
- 用模板字符串替代多段
+拼接字符串,提升可读性 - 把循环变量收敛到循环内部声明,避免污染全局作用域
- 去掉无意义的嵌套判断,简化分支逻辑
优化后的参考代码:
function print99Bottles() { for (let count = 99; count > 0; count--) { // 统一处理当前数量、下一轮剩余数量的单复数 const currentBottleText = count === 1 ? 'bottle' : 'bottles'; const remainCount = count - 1; const remainBottleText = remainCount === 1 ? 'bottle' : 'bottles'; console.log(`${count} ${currentBottleText} of beer on the wall, ${count} ${currentBottleText} of beer. Take one down and pass it around, `); if (remainCount > 0) { console.log(`${remainCount} ${remainBottleText} of beer on the wall.`); } else { console.log(`no more bottles of beer on the wall.`); } } } print99Bottles();
优化后代码行数减少近一半,没有重复逻辑,变量作用域清晰,后续修改文案或者调整逻辑只需要改对应位置即可,不需要在多个重复分支里同步修改。
内容的提问来源于stack exchange,提问作者Arun Agasti
相关产品推荐
相关产品推荐

