Udacity测验JavaScript三角形生成代码疑问解析及执行流程模拟
关于Udacity JavaScript三角形生成代码的疑问与解析
问题背景
我正在Udacity平台学习JavaScript,在一次测验中没能独立完成题目,于是查看了官方参考答案,但仍有部分代码逻辑搞不懂,先把代码贴出来:
// creates a line of * for a given length function makeLine(length) { var line = ""; for (var j = 1; j <= length; j++) { line += "* "; } return line + "\n"; } // your code goes here. Make sure you call makeLine() in your own code. function buildTriangle(length) { // Let's build a huge string equivalent to the triangle var triangle = ""; //Let's start from the topmost line var lineNumber = 1; for(lineNumber=1; lineNumber<=length; lineNumber++){ // We will not print one line at a time. // Rather, we will make a huge string that will comprise the whole triangle triangle = triangle + makeLine(lineNumber); } return triangle; } // test your code by uncommenting the following line // Note that the function buildTriangle() must return a string // because the console.log() accepts a string argument console.log(buildTriangle(10));
我的具体疑问
- 我理解
makeLine()函数会根据传入的length值生成对应长度的星号行,但搞不懂triangle = triangle + makeLine(lineNumber)这行代码的工作原理:它和makeLine函数中的line += "* "是否作用相同?如果作用相同的话,为什么输出结果是正确的? - 另外,请纠正我的理解误区:
makeLine(length)和buildTriangle(length)中的length变量是否因作用域不同而属于不同的变量?我能否将buildTriangle函数的参数名修改为passedValueToMakeLineFunc? - 恳请模拟JavaScript引擎的运行过程,用通俗易懂的语言分步讲解这段代码的执行流程。
解答部分
1. 关于triangle = triangle + makeLine(lineNumber)和line += "* "的异同
这两行核心逻辑是一样的:都是字符串拼接,但作用的对象和层级完全不同,这也是结果正确的原因:
line += "* "是在makeLine函数内部,给一个空字符串line逐个添加*,最终生成一行星号(比如length=3时,得到* * * \n);triangle = triangle + makeLine(lineNumber)是在buildTriangle函数里,把makeLine生成的每一行星号字符串,逐个拼接到triangle这个大字符串里。比如第一次循环(lineNumber=1),triangle从空变成* \n;第二次循环(lineNumber=2),变成* \n* * \n,以此类推,最终把所有行拼起来形成完整的三角形字符串。
简单说,前者是拼一行的星号,后者是把一行行的星号拼起来成整个三角形,虽然都是字符串累加,但处理的是不同层级的内容,所以结果是正确的。
2. 关于两个length变量的作用域,以及参数名修改的问题
你的理解完全正确!这两个length是毫无关系的变量,因为它们分别属于各自函数的局部作用域:
makeLine里的length是它自己的参数,只在makeLine函数内部有效;buildTriangle里的length是它的参数,只在buildTriangle内部有效。两者名字相同但互不干扰,就像两个同名的文件放在不同文件夹里,不会混淆。
当然可以把buildTriangle的参数名改成passedValueToMakeLineFunc,完全没问题!修改后代码可以写成:
function buildTriangle(passedValueToMakeLineFunc) { var triangle = ""; var lineNumber = 1; for(lineNumber=1; lineNumber<=passedValueToMakeLineFunc; lineNumber++){ triangle = triangle + makeLine(lineNumber); } return triangle; }
只要在函数内部正确使用这个参数名(比如循环条件里用它),就不会影响功能,参数名只是个“占位符”,你可以随便起有意义的名字。
3. 模拟JavaScript引擎分步执行流程(以console.log(buildTriangle(10))为例)
我们一步一步来走:
- 全局初始化阶段:JS引擎先扫描整个代码,把
makeLine和buildTriangle两个函数定义加载到内存里,准备好被调用。 - 调用
buildTriangle(10):- 给
buildTriangle的参数赋值为10,创建函数的局部作用域,里面初始化变量triangle = "",lineNumber = 1。 - 进入循环:
lineNumber从1开始,到10结束,每次循环执行这些操作:- 第一次循环(lineNumber=1):
- 调用
makeLine(1):进入makeLine的局部作用域,参数length=1,创建line=""。 - 执行
makeLine里的循环:j从1到1,循环1次,line变成*,然后返回* \n(加上换行符)。 - 回到
buildTriangle,把返回的字符串拼到triangle上:triangle从空变成* \n。
- 调用
- 第二次循环(lineNumber=2):
- 调用
makeLine(2):length=2,line从空开始,循环2次,变成* *,返回* * \n。 triangle变成* \n* * \n。
- 调用
- ...以此类推:每次循环
lineNumber加1,调用makeLine(lineNumber)生成对应长度的星号行,拼到triangle里。 - 第十次循环(lineNumber=10):调用
makeLine(10)生成10个*加换行,拼到triangle末尾,此时triangle已经是包含10行星号的完整字符串。
- 第一次循环(lineNumber=1):
- 循环结束,
buildTriangle返回这个完整的triangle字符串。
- 给
- 执行
console.log():把返回的字符串打印到控制台,你就看到了一个由星号组成的三角形。
内容的提问来源于stack exchange,提问作者Tima Da
相关产品推荐
相关产品推荐

