关于validBraces函数中if条件语句内stack.pop()执行原理的技术问询
validBraces函数中stack.pop()的执行逻辑 首先放上待分析的代码:
function validBraces(braces) { var matches = { '(': ')', '{': '}', '[': ']' }; var stack = []; var currentChar; for (var i = 0; i < braces.length; i++) { currentChar = braces[i]; if (matches[currentChar]) { stack.push(currentChar); } else { if (currentChar !== matches[stack.pop()]) { return false; } } } return stack.length === 0; }
你的疑问:
我对这段代码的理解是:
currentChar !== matches[stack.pop()]用于检查当前字符是否与栈(stack)数组最后一个元素对应的闭合括号匹配,若匹配则弹出栈的最后一个元素。但代码中并未编写匹配成功时的条件分支(例如if(currentChar == matches[stack.pop()]) {stack.pop()}这样的结构)。那么,即便没有匹配成功的条件分支,stack.pop()是否仍会在if条件语句中执行?它的具体执行逻辑是怎样的?
这是个非常好的观察点!核心答案是:不管if条件最终成立与否,stack.pop()都会先执行,这是由JavaScript表达式的执行顺序决定的,我来给你拆解清楚:
表达式的执行顺序
当代码执行到currentChar !== matches[stack.pop()]时,JavaScript会按照从内到外的顺序计算所有嵌套表达式:- 先调用
stack.pop(),把栈顶的左括号元素弹出来(这一步会直接修改栈的内容) - 再用弹出的这个元素作为key,从
matches对象里取出对应的闭合括号 - 最后把这个取出的闭合括号和
currentChar做不等比较
- 先调用
匹配成功时的逻辑
如果当前闭合括号和弹出的左括号对应的闭合括号相等(比如currentChar是),弹出的是(,matches['(']就是)),那么currentChar !== matches[stack.pop()]的结果是false,不会进入if块里的return false。这时候栈已经被pop()修改过了——匹配的左括号已经被移除,完全符合我们的需求,不需要额外写分支去重复pop()。匹配失败时的逻辑
如果两者不相等(比如currentChar是],弹出的是(),那么比较结果是true,直接执行return false,终止函数,说明括号不合法。
举个实际的小例子:
假设当前栈是['('],currentChar是):
- 执行
stack.pop(),栈变成空,返回值是'(' - 取
matches['(']得到')' - 比较
')' !== ')',结果为false,跳过if块,循环继续
另外还要提一句:你之前设想的if(currentChar == matches[stack.pop()]) {stack.pop()}是有问题的——因为这样写的话,stack.pop()会执行两次:一次在条件判断里,一次在if块里,会错误地多弹出一个元素,反而破坏栈的结构。原代码的写法刚好利用了表达式的执行顺序,用一次pop()同时完成了“取出栈顶元素”和“检查匹配”两个操作,非常巧妙。
内容的提问来源于stack exchange,提问作者echo

