根据给定的字符串,修改一个多层嵌套对象对应的属性值

题目描述

我在localStorage里面储存用户信息userInfo,要封装一个修改userInfo的方法

相关代码

// userInfof里面有很多信息
var userInfo= {
    id:'123',
    name:'Jim',
    info:{
        address:{
            home:'地王大厦',
            work:{
               workDays:'腾讯大厦',
               weekend:'阿里巴巴大厦',
               festival:'百度大厦',
            },
        },
        money:{
            balance:0,// 余额
            redPacket:0,// 红包
            integral:0,// 积分            
        }
    }
}
// 比如修改localStorage.userInfo.info.address.work.workDays为京东大厦,则
editFn('userInfo.info.address.work.workDays','京东大厦');

// 比如修改localStorage.userInfo.info.money.balance为888,则
editFn('userInfo.info.money.balance','888');

你期待的结果是什么?

这个editFn方法改怎么写?
阅读 6.5k
3 个回答
function editFn(path, value, obj) {
    const arr = path.split('.')
    const len = arr.length - 1
    arr.reduce((cur, key, index) => {
            if (!(cur[key]))
                throw `${key} 不存在!`
            if (index === len) {
                cur[key] = value
            }
            return cur[key]
        }, obj)
}

editFn('info.address.work.workDays','京东大厦', userInfo);

这里要求 userInfo 已经是解析后的一个 object,因此 path 部分不能再以 userInfo 开头。

再一次这个没有处理数组的情形,需要留意。

如果你非要用这种方法来修改的话……,首先要明确一个,就是LocalStorage存储的是字符串
所以我假设你的LocalStorage里面存的对象是JSON.stringify()转出的json

function RewriteLS(LSkey,fn){
    //Write接收一个回调函数作为参数,回调函数的参数为要修改的obj
    if(!localStorage[LSkey]){
        localStorage[LSkey] = JSON.stringify({});
    }
    let Obj = JSON.parse(localStorage[LSkey]);//这里应当先判断isJSON,我就省略了,懒得写
    Obj = fn(Obj)||Obj; //这里可以随你return,直接用引用修改的话就不用return了
    console.log(Obj);
    localStorage[LSkey] = JSON.stringify(Obj)
}
function editFn(path,value){
    let pathArr = path.split(".");
    RewriteLS(pathArr.splice(0,1),(obj)=>{
        try{
            eval("obj."+pathArr.join(".")+"=value");
        }catch(e){
            //中间的path可能出错。
            throw e;
        }
    })
}

我直接使用了eval来处理赋值,如果你想的话,循环或者递归来resolve路径也是可以的。
但是你所说的传递一个字符串路径的方式我十分不推荐。

你可以看到我单独封装了一个RewriteLS函数,使用该函数

RewriteLS("userInfo",obj=>{
    //在这里对obj的属性进行处理
});

来处理的话会更加灵活,也更安全。

新手上路,请多包涵
if (!(cur[key]))
                throw `${key} 不存在!`

这里不太合理.如果给一个全新对象赋值嵌套属性的话,直接崩溃.
改造一下:

if (!(cur[key])) {  
    try {  
        Object.defineProperty(cur, key, {value: {}, writable: true, configurable: true, enumerable: true});  
  } catch (e) {  
        console.error(e);  
  }  
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题