JavaScript递归遍历查找节点值时出现undefined错误排查
问题:递归查找JSON节点值时数组处理导致的undefined错误
我有如下嵌套JSON结构:
var content = {"id": "RkktMTA1OC0wNTE3QElNQi82NTAwNC9YLzAwSDc","name": "FI-1058-0517","category": "FTTH","place": {"id": "SU1CLzY1MDA0L1gvMDBINw","href": "/geographicSite/SU1CLzY1MDA0L1gvMDBINw","name": "IMB/65004/X/00H7","isSiteInfoAvailable": true,"place": [{"geographicSubAddress": [{"internalBuildingReference": "SSS0100000000000198332600","internalFloorReference": "","buildingName": "_NA_","levelNumber": "0","levelType": "floor","subUnit": [{"subUnitNumber": "_NA_","subUnitType": "staircase","internalReference": "SSS0100000000000198332601","@type": "GeographicSubAddressUnitExtended","@baseType": "GeographicSubAddressUnit"}],"@type": "GeographicSubAddressBuilding"}],"@type": "GeographicAddress"}],"relatedParty": [{"id": "FI","@referredType": "OI"}],"@type": "GeographicSiteBuilding","@baseType": "GeographicSite"},"resourceStatus": "En service","usageState": "Actif","developerOutletReference": "","toBeTicketed": false,"resourceRelationship": [{"id": "PT 000629","relationshipType": "Connected PBO","href": "/resource/pbo/UFQgMDAwNjI5QEZJLTY1MDU2LTAwMDM","@referredType": "ResourcePbo"},{"id": "FI-65056-0003","relationshipType": "Connected PM","href": "/resource/pm/RkktNjUwNTYtMDAwMw","@referredType": "ResourcePm"}],"nonOapcInfo": {"startOperatingDate": "2023-04-01","endOperatingDate": null,"predecessorIAR": ""},"hasFiberOpticDrawer": "","description": "","@baseType": "Resource","@type": "ResourcePto","FTTHLineStatus": ["existant","actif","raccordable","commercialisable"],"href": "/resource/pto/RkktMTA1OC0wNTE3QElNQi82NTAwNC9YLzAwSDc"}
我写了一个递归遍历查找节点值的PropertyExists函数,代码如下:
PropertyExists: function (obj, Field){var DataField = Field.split('.');if (DataField.length == 1){if (typeof obj === 'object' && obj !== null) {if (obj.hasOwnProperty(Field) && typeof obj[Field] === 'string') {return obj[Field].toLowerCase();}for (var p in obj) {console.log(p)if ($S.PropertyExists(obj[p], Field)) {console.log(obj[p])console.log(Field)return obj[p][Field].toLowerCase(); // Error line}}}return false;} else {if (typeof obj === 'object' && obj !== null) {if (obj.hasOwnProperty(DataField[0]) && obj[DataField[0]].hasOwnProperty(DataField[1]) && typeof obj[DataField[0]][DataField[1]] === 'string') {return obj[DataField[0]][DataField[1]].toLowerCase();}for (var p in obj) {if ($S.PropertyExists(obj[p], Field)) {return obj[p][DataField[0]][DataField[1]].toLowerCase();}}}return false;}}
执行console.log(PropertyExists(content, 'name'))时能正常返回IMB/65004/X/00H7,但执行console.log(PropertyExists(content, 'buildingName'))时抛出错误:obj[p][Field] is undefined。日志显示节点已被找到,但因为数组处理的问题无法返回正确值,求解决提示。
问题分析与修复方案
错误原因
- 未处理数组类型节点:当遍历到
place、geographicSubAddress这类数组时,obj[p]是数组对象,你直接将其当作普通对象处理。递归找到buildingName后,试图通过obj[p][Field]取值,但数组本身没有buildingName属性,因此报undefined。 - 递归返回逻辑错误:递归调用
$S.PropertyExists(obj[p], Field)返回有效值时,你没有直接返回这个结果,反而尝试重新通过obj[p][Field]取值,这在数组场景下必然失败。
修复后的函数
PropertyExists: function(obj, Field) { var DataField = Field.split('.'); // 处理单层字段(如'buildingName') if (DataField.length === 1) { if (typeof obj === 'object' && obj !== null) { // 检查当前对象是否包含目标字段且为字符串 if (obj.hasOwnProperty(Field) && typeof obj[Field] === 'string') { return obj[Field].toLowerCase(); } // 遍历对象所有属性 for (var p in obj) { var val = obj[p]; // 处理数组:遍历每个元素递归查找 if (Array.isArray(val)) { for (var item of val) { var result = $S.PropertyExists(item, Field); if (result !== false) { return result; } } } // 处理子对象:直接递归查找 else if (typeof val === 'object' && val !== null) { var result = $S.PropertyExists(val, Field); if (result !== false) { return result; } } } } return false; } // 处理嵌套字段(如'place.name') else { if (typeof obj === 'object' && obj !== null) { // 检查嵌套路径是否存在且目标值为字符串 if (obj.hasOwnProperty(DataField[0]) && typeof obj[DataField[0]] === 'object' && obj[DataField[0]] !== null && obj[DataField[0]].hasOwnProperty(DataField[1]) && typeof obj[DataField[0]][DataField[1]] === 'string') { return obj[DataField[0]][DataField[1]].toLowerCase(); } // 遍历对象所有属性,处理数组和子对象 for (var p in obj) { var val = obj[p]; if (Array.isArray(val)) { for (var item of val) { var result = $S.PropertyExists(item, Field); if (result !== false) { return result; } } } else if (typeof val === 'object' && val !== null) { var result = $S.PropertyExists(val, Field); if (result !== false) { return result; } } } } return false; } }
关键修复点
- 新增数组处理逻辑:遍历对象属性时,判断如果是数组则逐个遍历元素进行递归查找,覆盖JSON中的数组嵌套场景。
- 修正递归返回逻辑:递归调用后直接返回结果,不再尝试通过
obj[p][Field]重新取值,避免数组场景下的属性不存在错误。 - 增强空值判断:处理嵌套字段时,增加对中间对象的非空校验,避免空指针异常。
内容的提问来源于stack exchange,提问作者BlackPage
相关产品推荐
相关产品推荐

