实现 getValue/setValue 函数来获取path对应的值
通过路径字符串安全地获取和设置对象深层嵌套属性的值
问题
在实际开发中,我们经常需要访问对象的深层嵌套属性,例如 obj.a.b.c。但直接访问可能会因为中间某个属性不存在而报错。我们需要实现两个工具函数:
getValue(obj, path, defaultValue): 根据路径安全地获取对象属性值setValue(obj, path, value): 根据路径设置对象属性值
解答
/**
* 根据路径获取对象属性值
* @param {Object} obj - 目标对象
* @param {String} path - 属性路径,支持 'a.b.c' 或 'a[0].b' 格式
* @param {*} defaultValue - 默认值
* @returns {*} 返回对应路径的值,如果不存在则返回默认值
*/
function getValue(obj, path, defaultValue = undefined) {
// 将路径转换为数组,支持 'a.b.c' 和 'a[0].b' 两种格式
const keys = path.replace(/\[(\d+)\]/g, '.$1').split('.');
let result = obj;
// 逐层访问对象属性
for (let key of keys) {
// 如果当前层级为 null 或 undefined,返回默认值
if (result == null) {
return defaultValue;
}
result = result[key];
}
// 如果最终结果为 undefined,返回默认值
return result === undefined ? defaultValue : result;
}
/**
* 根据路径设置对象属性值
* @param {Object} obj - 目标对象
* @param {String} path - 属性路径,支持 'a.b.c' 或 'a[0].b' 格式
* @param {*} value - 要设置的值
* @returns {Object} 返回修改后的对象
*/
function setValue(obj, path, value) {
// 将路径转换为数组
const keys = path.replace(/\[(\d+)\]/g, '.$1').split('.');
const lastKey = keys.pop();
let current = obj;
// 逐层创建不存在的对象
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const nextKey = keys[i + 1];
// 如果当前属性不存在或不是对象,则创建新对象
if (current[key] == null || typeof current[key] !== 'object') {
// 判断下一个 key 是否为数字,决定创建对象还是数组
current[key] = /^\d+$/.test(nextKey) ? [] : {};
}
current = current[key];
}
// 设置最终的值
current[lastKey] = value;
return obj;
}
使用示例
// 测试对象
const obj = {
a: {
b: {
c: 'hello'
}
},
arr: [1, 2, { name: 'test' }]
};
// getValue 示例
console.log(getValue(obj, 'a.b.c')); // 'hello'
console.log(getValue(obj, 'a.b.d', 'default')); // 'default'
console.log(getValue(obj, 'arr[0]')); // 1
console.log(getValue(obj, 'arr[2].name')); // 'test'
console.log(getValue(obj, 'x.y.z', 'not found')); // 'not found'
// setValue 示例
const newObj = {};
setValue(newObj, 'a.b.c', 100);
console.log(newObj); // { a: { b: { c: 100 } } }
setValue(newObj, 'arr[0]', 'first');
console.log(newObj); // { a: { b: { c: 100 } }, arr: ['first'] }
setValue(newObj, 'user.info.name', 'John');
console.log(newObj);
// { a: { b: { c: 100 } }, arr: ['first'], user: { info: { name: 'John' } } }
// 修改已存在的值
setValue(obj, 'a.b.c', 'world');
console.log(obj.a.b.c); // 'world'
关键点
- 路径解析:使用正则表达式
/\[(\d+)\]/g将数组索引格式[0]转换为点号格式.0,统一处理 - 安全访问:在 getValue 中使用
== null判断,同时处理null和undefined的情况 - 默认值处理:当路径不存在或值为
undefined时返回默认值 - 自动创建对象:在 setValue 中,如果路径上的对象不存在,自动创建中间对象
- 智能类型判断:根据下一个 key 是否为数字,决定创建对象还是数组
- 链式路径:支持
a.b.c和a[0].b两种路径格式的混合使用 - 不可变性考虑:如果需要不修改原对象,可以在 setValue 开始时先深拷贝对象
目录