← 返回题目列表

如何手写根据路径 get 和 set 对象属性?

中等 第 24 / 27 题 更新于 2026/07/29
手写代码对象路径解析工具函数

简化版

根据路径 get/set 对象属性,就是支持用 a.b[0].c 这样的字符串读取或设置深层值。实现思路是先把路径解析成 key 数组,再逐层访问。get 遇到 null/undefined 返回默认值;set 遇到不存在的中间层就创建对象或数组。边界包括数组下标、空路径、默认值、原型污染风险。

详细版

关键步骤是路径标准化。

输入路径解析结果
a.b.c["a", "b", "c"]
a[0].b["a", "0", "b"]
user.name["user", "name"]
function parsePath(path: string) {
  return path.replace(/\[(\w+)\]/g, '.$1').split('.').filter(Boolean)
}

function get(obj: any, path: string, defaultValue?: unknown) {
  const keys = parsePath(path)
  let cur = obj
  for (const key of keys) {
    if (cur == null) return defaultValue
    cur = cur[key]
  }
  return cur === undefined ? defaultValue : cur
}

这类工具函数不要忘了安全边界,__proto__constructorprototype 不能随便 set。

完整版教学

一、题目考察点

这题考对象访问、字符串解析、边界处理和安全意识。很多表单库、配置系统和校验库都会用类似能力。

例如:

get(user, 'profile.address.city')
set(form, 'items[0].name', 'Book')

二、路径解析

最常见做法是把中括号写法转换成点写法。

function parsePath(path: string) {
  return path
    .replace(/\[(\w+)\]/g, '.$1')
    .split('.')
    .filter(Boolean)
}

这能覆盖大多数面试场景,但完整 lodash 级别路径解析会更复杂,例如引号、转义字符和特殊 key。

三、get 实现

get 逐层访问即可。关键是遇到 nullundefined 要停止,避免报错。

function getValue(obj: any, path: string, defaultValue?: unknown) {
  let cur = obj
  for (const key of parsePath(path)) {
    if (cur == null) return defaultValue
    cur = cur[key]
  }
  return cur === undefined ? defaultValue : cur
}

注意 null 是否返回默认值,要看约定。常见实现只在最终结果为 undefined 时返回默认值。

四、set 实现

set 要创建中间对象。

function setValue(obj: any, path: string, value: unknown) {
  const keys = parsePath(path)
  let cur = obj
  keys.forEach((key, index) => {
    if (index === keys.length - 1) {
      cur[key] = value
      return
    }
    const nextKey = keys[index + 1]
    if (cur[key] == null) cur[key] = /^\d+$/.test(nextKey) ? [] : {}
    cur = cur[key]
  })
  return obj
}

如果下一个 key 是数字,可以创建数组,否则创建对象。

五、原型污染风险

如果允许用户传任意 path,set(obj, '__proto__.polluted', true) 可能污染对象原型。

因此 set 时要拦截危险 key:

const dangerous = new Set(['__proto__', 'prototype', 'constructor'])

命中危险 key 应直接拒绝。

六、工程扩展

成熟工具还会支持:

  • 路径数组:['a', 'b', 0, 'c']
  • 带引号路径:a["b.c"]
  • 不修改原对象的 immutable set。
  • TypeScript 类型推导。
版本特点
面试基础版点路径 + 中括号数字
工程增强版安全拦截 + immutable
库级实现完整路径语法 + 类型

七、常见误区与追问

  • 误区:直接 split 点号就够。 a[0].b、空路径和特殊 key 都要考虑。
  • 误区:set 可以无条件创建任意 key。 用户输入路径时必须防原型污染。
  • 误区:get 遇到 falsy 就返回默认值。 0false、空字符串都是有效值,不能误判。
  • 追问:如何支持数组路径? 如果 path 本身是数组,就直接遍历,不需要解析字符串。
  • 追问:如何 immutable set? 沿路径复制每一层对象或数组,最后返回新对象。
  • 追问:为什么 constructor 危险? 它可能通向原型链,造成原型污染风险。

八、加强记忆

路径 get/set 记成“先解析,再逐层走”。get 要安全短路,set 要补中间层,还要拦截原型污染。不要把 falsy 当成不存在。