除作用域外,JS循环内外声明变量的差异?附Mexican Wave案例
循环内外声明变量的差异:以Mexican Wave函数为例
问题背景
需要实现一个将字符串转换为“墨西哥波浪”的函数,示例效果:输入 "hello" 应返回 ['Hello', 'hEllo', 'heLlo', 'helLo', 'hellO']。
正确实现(splitStr声明在循环内)
function wave(str) { let waveArr = []; for (let i = 0; i < str.length; i++) { const splitStr = str.split(""); // 声明在循环内 if (splitStr[i] !== " ") { splitStr[i] = splitStr[i].toUpperCase(); waveArr.push(splitStr.join("")); } } console.log(waveArr); return waveArr; } wave("hello"); // 返回 ['Hello', 'hEllo', 'heLlo', 'helLo', 'hellO']
异常实现(splitStr声明在循环外)
将splitStr移到循环外后,返回结果变为 ['Hello', 'HEllo', 'HELlo', 'HELLo', 'HELLO'],每次迭代会保留之前已大写的字符,导致多个字符同时大写:
function wave(str) { let waveArr = []; const splitStr = str.split(""); // 声明在循环外 for (let i = 0; i < str.length; i++) { if (splitStr[i] !== " ") { splitStr[i] = splitStr[i].toUpperCase(); waveArr.push(splitStr.join("")); } } console.log(waveArr); return waveArr; } wave("hello"); // 返回 ['Hello', 'HEllo', 'HELlo', 'HELLo', 'HELLO']
问题解答
结果差异的原因
splitStr是数组,属于引用类型:
- 循环内声明时,每次迭代都会调用
str.split("")生成全新的数组副本,修改当前索引的字符后,这个副本会被加入结果数组,不会影响其他迭代的数组。 - 循环外声明时,整个循环共用同一个数组引用。每次迭代修改索引
i的字符为大写后,修改会永久保留在原数组中。下一次迭代时,数组里已有之前大写的字符,再修改新索引就会出现多个字符大写的情况。
除作用域外,循环内外声明变量的其他区别
- 引用类型的状态保留:数组、对象这类引用类型,循环外声明会复用同一个引用,每次修改都会改变其内部状态;循环内声明则每次创建新实例,状态互不干扰。
- 内存与性能:
- 循环内声明值类型(字符串、数字等)时,现代JS引擎会做优化,性能差异极小;但创建复杂对象/数组时,频繁生成实例可能有微小性能开销。
- 循环外声明可减少实例创建次数,但需注意引用类型的状态污染问题。
- 变量生命周期:循环内用
const/let声明的变量,仅在当前迭代的块级作用域内有效,迭代结束后会被引擎回收;循环外声明的变量会在整个函数作用域内存在,直到函数执行完毕。
内容的提问来源于stack exchange,提问作者chickpea
相关产品推荐
相关产品推荐

