LeetCode最长公共前缀问题:遍历字符串数组遇TypeError的原因及解决
为什么第一个循环返回
undefined,第二个循环直接报错?如何避免? 这问题问得挺细致的,咱们先把两个循环的本质区别拆解清楚,再聊怎么避免这类运行时错误~
一、两个循环表现不同的核心原因
1. 第一个循环:访问存在的对象的不存在属性
你的第一个循环里,l[0]是明确存在的字符串"str"。在JavaScript中,字符串属于类数组对象,当你访问它的索引超过自身长度时(比如"str"[3]),JS不会抛出错误,只会返回undefined——因为这个位置确实没有字符,但字符串本身是存在的对象,所以可以安全地读取它的“不存在的属性”。
所以你看到循环里i从3到5时,typeof l[0][i]输出undefined,这是正常行为。
2. 第二个循环:访问不存在的对象的属性
第二个循环里,l[3]本身就是undefined(因为你的数组l只有两个元素,索引0和1)。当你试图执行l[3][i]时,相当于在尝试读取undefined的属性[i]——但undefined不是对象,JS不允许读取非对象的属性,所以直接抛出TypeError: Cannot read property '0' of undefined。
简单总结:
- 「存在的对象 + 不存在的属性」→ 返回
undefined - 「不存在的对象 + 任何属性」→ 直接报错
二、如何避免这类运行时错误?
针对你解决「最长公共前缀」的场景,以及通用的嵌套属性访问场景,给你两种思路:
1. 针对最长公共前缀的专项解法
解决这个问题的核心是先确保要访问的字符串存在,再检查对应位置的字符,推荐两种实现方式:
方式一:逐字符校验(更直观)
function longestCommonPrefix(strs) { // 边界处理:空数组直接返回空字符串 if (!strs || strs.length === 0) return ""; // 以第一个字符串为基准,遍历每个字符位置 for (let i = 0; i < strs[0].length; i++) { const currentChar = strs[0][i]; // 检查数组中所有其他字符串的对应位置 for (let j = 1; j < strs.length; j++) { // 两个终止条件: // 1. 当前字符串长度不足(没有第i个字符) // 2. 当前字符和基准字符不匹配 if (i >= strs[j].length || strs[j][i] !== currentChar) { // 返回基准字符串的前i个字符 return strs[0].slice(0, i); } } } // 如果基准字符串全匹配,直接返回它 return strs[0]; }
方式二:逐步缩短前缀(更简洁)
function longestCommonPrefix(strs) { if (strs.length === 0) return ""; // 初始前缀为第一个字符串 let prefix = strs[0]; // 遍历数组中剩下的每个字符串 for (let i = 1; i < strs.length; i++) { // 当当前字符串不包含当前前缀时,缩短前缀 while (strs[i].indexOf(prefix) !== 0) { prefix = prefix.slice(0, prefix.length - 1); // 如果前缀被缩短为空,直接返回空 if (prefix === "") return ""; } } return prefix; }
2. 通用的嵌套属性访问防错技巧
如果是其他场景需要访问类似arr[x][y]的嵌套结构,可以用以下方法避免报错:
- 可选链操作符(ES2020+):用
arr[x]?.[y]代替arr[x][y],如果arr[x]是undefined或null,表达式直接返回undefined,不会报错。比如你的测试代码可以改成:console.log('typeof: ', i, typeof l[3]?.[i]); - 前置条件判断:手动检查每一层是否存在:
if (l[3] !== undefined) { console.log('typeof: ', i, typeof l[3][i]); } else { console.log('typeof: ', i, 'undefined'); }
内容的提问来源于stack exchange,提问作者tr2000
相关产品推荐
相关产品推荐

