如何定位嵌套对象属性链中undefined值的出现位置?
高效定位属性链undefined节点的解决方案
针对你需要在运行时定位属性链中undefined节点的需求,以下是几种比逐行assert更高效的实现方式:
方案1:自定义可复用链式检查函数
封装一个通用函数,接收目标对象和属性路径数组,逐个校验每个节点,遇到不存在的节点时抛出包含具体路径的错误。
import assert from 'assert'; // 通用属性链检查函数 function checkPropertyChain(obj, path) { let current = obj; for (const [index, key] of path.entries()) { assert(current != null, `属性链中断:路径[${path.slice(0, index).join('.')}]之后,节点「${key}」不存在`); current = current[key]; } return current; } export function setPropertyOffer( db: Record<string, any>, customer: number, offerId: number, key: string, value: number | string, ) { // 原有类型校验不变 assert(typeof db === 'object'); assert(typeof customer === 'number'); assert(typeof offerId === 'number'); assert(typeof key === 'string'); assert(typeof value === 'string' || typeof value === 'number'); // 校验到offerId节点,再单独校验目标key const offerNode = checkPropertyChain(db, [customer, 'offers', offerId]); assert(offerNode[key] != null, `节点「${key}」在offer ${offerId}中不存在`); offerNode[key] = value; }
优势:复用性强,支持任意长度的属性链,错误信息清晰指向问题节点。
方案2:结合Lodash工具函数简化校验
利用Lodash的_.has方法检查路径是否存在,批量定义需要校验的子路径,替代逐行assert:
import assert from 'assert'; import _ from 'lodash'; export function setPropertyOffer( db: Record<string, any>, customer: number, offerId: number, key: string, value: number | string, ) { // 原有类型校验不变 assert(typeof db === 'object'); assert(typeof customer === 'number'); assert(typeof offerId === 'number'); assert(typeof key === 'string'); assert(typeof value === 'string' || typeof value === 'number'); // 定义需要校验的所有子路径 const checkPaths = [ [customer], [customer, 'offers'], [customer, 'offers', offerId], [customer, 'offers', offerId, key] ]; // 批量校验每个路径节点 for (const path of checkPaths) { assert(_.has(db, path), `属性链节点「${path.join('.')}」不存在`); } db[customer].offers[offerId][key] = value; }
优势:借助成熟工具函数减少重复代码,错误信息明确,实现成本低。
方案3:Proxy自动追踪属性链(全局通用场景)
通过Proxy包装对象,自动拦截属性访问并追踪路径,遇到不存在的节点时直接抛出错误,无需手动定义校验路径:
import assert from 'assert'; // 创建带路径追踪的Proxy function createTracedProxy(obj, currentPath = []) { return new Proxy(obj, { get(target, prop) { const newPath = [...currentPath, prop]; const value = target[prop]; assert(value != null, `属性链中断:路径「${newPath.join('.')}」不存在`); // 若节点是对象,继续包装Proxy以追踪后续路径 if (typeof value === 'object' && value !== null) { return createTracedProxy(value, newPath); } return value; } }); } export function setPropertyOffer( db: Record<string, any>, customer: number, offerId: number, key: string, value: number | string, ) { // 原有类型校验不变 assert(typeof db === 'object'); assert(typeof customer === 'number'); assert(typeof offerId === 'number'); assert(typeof key === 'string'); assert(typeof value === 'string' || typeof value === 'number'); // 用Proxy包装db,自动追踪属性访问 const tracedDb = createTracedProxy(db); tracedDb[customer].offers[offerId][key] = value; }
优势:代码最简洁,无需手动维护校验路径,适合多个函数需要属性链校验的场景。
内容的提问来源于stack exchange,提问作者Sandra Schlichting
相关产品推荐
相关产品推荐

