实现Lodash之get方法

580 阅读1分钟

要求

var obj = {
    a:{
        b:234
    },
    b:[
        {
            b1:123,
            b2:456
        },
        {
            b1:123,
            b2:456
        }
    ],
    c:[
        [
            {
                c1:7890
            }
        ],
        [
            {
                c1:123456
            }
        ]
    ]
}
get(obj,'a.b')//返回234
get(obj,'b[1].b1')//返回123
get(obj,'c[0][0].c1')//返回7890
get(obj,'c[1][0].c1')//返回123456

Code

数据劫持

function observe(data) {
    if (!data || typeof data !== 'object') {
            return;
    }
    Object.keys(data).forEach(key => {
            defineReactive(data, key, data[key]);
            observe(data[key]);
    });
}

function defineReactive(data, key, value) {
    Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get() {
                    return value;
            },
            set(newValue) {
                    if (newValue !== value) {
                            observe(newValue);
                            value = newValue;
                    }
            }
    });
}

get方法

function get(data,paths){
    observe(obj);
    let _reg = /\[(\d*?)\]/gim,
            isExitsArray = paths.match(_reg);//路径中是否存在数组,[]
    if(isExitsArray){
            let _paths = paths.split('.');
            return _paths.reduce((prev,item,index,arr)=>{
                    if(item.match(_reg)){
                            // 字符串数组下表
                            let arrIndexs = [];
                            item.match(_reg).forEach((regItem)=>{
                                    arrIndexs.push(parseInt(regItem.slice(1)));
                            });
                            // 属性名
                            let key = item.slice(0,item.indexOf('['));
                            return arrIndexs.reduce((prevIdx,idx,_idx,arrIndexs)=>{
                                    return prevIdx[idx];
                            },prev[key]);
                    }else{
                            // 属性名
                            return prev[item];
                    }
            },data)
    }else{
            let _paths = paths.split('.');
            let res = _paths.reduce((prev,item,index,arr)=>{
                    return prev[item];
            },data);
            return res;
    }
}