簡體   English   中英

在可變深度下更新對象值的更好方法

[英]Better way to update an object's value at a variable depth

我正在開發一些使用處理程序讀取/寫入localStorage中的信息的軟件。 您可以在此處找到一個有效的示例: http : //jsbin.com/wifucugoko/edit?js,console

我的問題是下面的代碼段( 關注switch語句 ):

_t.set = function(path, value) { // Update a single value or object
        if (~path.indexOf(".")) {
            let o = path.split(".")[0],
                p = this.get(o),
                q = path.split(".").slice(1);
            switch (q.length) { 
            // There has to be a better way to do this... 
                case 1:
                    p[q[0]] = value; 
                    break;
                case 2:
                    p[q[0]][q[1]] = value; 
                    break;
                case 3:
                    p[q[0]][q[1]][q[2]] = value; 
                    break;
                case 4:
                    p[q[0]][q[1]][q[2]][q[3]] = value; 
                    break;
                case 5:
                    p[q[0]][q[1]][q[2]][q[3]][q[4]] = value; 
                    break;
                case 6: 
                    p[q[0]][q[1]][q[2]][q[3]][q[4]][q[5]] = value; 
                    break;
                default:  
                    return "error";
            }  
            b.setItem(o, JSON.stringify(p));
            return p;
        } else {
           b.setItem(path, JSON.stringify(value));
            return this.get(path);
        }
    };

我不會成為使用此代碼庫的唯一人,並且我正在嘗試使其他人更容易更新可以放置在localStorage 任何值。 現在,您可以使用諸如local.set('item.subitem.proeprty', 'value')類的值來更新值, 盡管上面的代碼可以做到這一點,但卻很丑陋且無法縮放

如何將該方法改進為(1)自動更新嵌套在任何深度的屬性,而不是編寫無限長的switch語句,以及(2)更新值后不將父對象與[object Object]綁在一起?


這個問題與我對localStorage使用無關 我最初將此問題發布在代碼審查中,這需要一個有效的上下文示例。 他們立即解決了這個問題,因為部分問題是,一旦您開始處理嵌套超過六個對象的值,我提供的代碼將無法正常工作。 盡管我可以無限期地繼續執行switch語句,但這正是我想要避免的

通過提供的三個示例,您將看到在一個位置設置值不會在其他位置刪除值:

 local.set('user.session.timeout', false);
 local.set('user.name', {first:'john', last:'doe', mi:'c'});
 local.set('user.PIN', 8675309);

所有這些值,盡管是在不同的時間設置的,僅是UPDATE或創建一個值,而不會清除其他位置的任何現有值。

對於我來說,最小的優化如下:

    if (~path.indexOf(".")) {
        let o = path.split(".")[0],
            p = this.get(o),
            q = path.split(".").slice(1),
            dist = p;
            q.forEach(function(item, index) {
                if (index < q.length - 1) {
                    dist = dist[item];
                } else {
                    dist[item] = value;
                }
            });
        b.setItem(o, JSON.stringify(p));
        return p;
    } else {

更換零件:

  1. 創建dist變量
  2. 硬編碼開關替換為foreach

您可以嘗試這樣的操作,如果路徑不存在,則值為null:

 function retreiveValueFromObject(path, object) { var pathList = path.split("."); var currentValue = object; var brokeEarly = false; for (var i = 0; i < pathList.length; i++) { if (currentValue[pathList[i]]) { currentValue = currentValue[pathList[i]]; } else { brokeEarly = true; break; } } return { value: currentValue, brokeEarly: brokeEarly }; } function setValueInObject(path, value, object) { var nestedObj = retreiveValueFromObject(path, object).value; var pathList = path.split("."); var finalKey = pathList[pathList.length - 1]; nestedObj[finalKey] = value; } var someObject = { a: { c: { d: "value" }, z: "c" }, b: { f: { x: "world" }, g: "hello" }, }; console.log(retreiveValueFromObject("bfx", someObject)); setValueInObject("bfy", "newValue", someObject); console.log(someObject); 

您正在尋找的是一點遞歸,我只是實現了update方法。

let localStorageHandler = function() {
    let b = window.localStorage,
         _t = this;
    _t.get = function(a) {
        try {
            return JSON.parse(b.getItem(a))
        } catch (c) {
            return b.getItem(a)
        }
    };

    function descendAndUpdate(obj, path, value) {
        let current = path[0],
            remainingPath = path.slice(1);
        // found and update
        if (obj.hasOwnProperty(current) && remainingPath.length === 0) {
            obj[current] = value;
        // found but still not there
        } else if (obj.hasOwnProperty(current)) {
            return descendAndUpdate(obj[current], remainingPath, value);
        }
        // if you want do add new properties use:
        // obj[current] = value;
        // in the else clause
        else {
            throw('can not update unknown property');
        }
    }

    _t.set = function(path, value) { // Update a single value or object
        if (~path.indexOf(".")) {
            let o = path.split(".")[0],
                p = this.get(o),
                q = path.split(".").slice(1);
            descendAndUpdate(p, q, value);
            console.log(p);
            b.setItem(o, JSON.stringify(p));
            return p;
        } else {
           b.setItem(path, JSON.stringify(value));
            return this.get(path);
        }
    };
    _t.remove = function(a) { // removes a single object from localstorage
        let c = !1;
        a = "number" === typeof a ? this.key(a) : a;
        a in b && (c = !0, b.removeItem(a));
        return c
    };
};
let local = new localStorageHandler();


// Create user and session info if it doesn't exist
let blankUser = new Object({
    alias: '',
    dob: '',
    PIN: '',
    level: 0,
    name: {
        first: '',
        last: '',
        mi:'',
    },
    session: {
        token: '',
        timeout: true,
        lastChange: Date.now()
    }
});

local.remove('user');

// Loads user data into localstorage
if (!local.get('user')) {
     local.set('user', blankUser);
}

local.set('user.session.timeout', false);
local.set('user.name', {first:'john', last:'doe', mi:'c'});
local.set('user.PIN', 8675309);

// new property
// local.set('user.sunshine', { 'like': 'always' });

console.log(local.get('user'));

我的一個朋友總是喜歡堆棧而不是遞歸,這是第二種選擇。 無論如何,我同意這里的許多評論。 您已經知道您的域模型。 除非您有很好的理由使用此方法,否則請花更多時間對數據庫中的這些對象進行序列化和反序列化。 我的印象是,您將能夠以更自然的方式處理數據,因為更新數據庫中字段的方面將被抽象化。

我目前正在從事類似的項目。 我正在做的是將數據存儲在我稱為WordMatrix( https://github.com/SamM/Rephrase/blob/master/WordMatrix.js )的東西中,也許您可​​以在解決方案中使用類似的東西。

我的項目是WIP,但下一步實際上是添加對localStorage的支持。 該項目本身是一個數據庫編輯器,可與鍵=>值存儲區一起使用。 您可以在此處查看其原型:( https://samm.github.io/Rephrase/editor.html

一旦實現了localStorage方面,我將更新這篇文章。

您的話題使我想起了另一個話題

為了增強我提供的答案 ,我建議您執行以下功能:

 // Function to get a nested element: function obj_get_path(obj, path) { return path.split('.').reduce((accu, val) => accu[val] || 'Not found', obj); } // Function to set a nested element: function obj_set_path(obj, path, value) { var result = obj; var paths = path.split('.'); var len = paths.length; for (var i = 0; i < len - 1; i++) { result = result[paths[i]] || {}; } result[paths[len - 1]] = value; return obj; } // Example object var obj = { name0: 'A name', level0: { name1: 'An other name', level1: { level2: { name3: 'Name to be changed', text3: 'Some other text' } } } } // Use of the function obj = obj_set_path(obj, 'level0.level1.level2.name3', 'Takit Isy'); obj = obj_set_path(obj, 'level0.level1.level2.new3', 'I'm a new element!'); var obj_level2 = obj_get_path(obj, 'level0.level1.level2'); // Consoling console.log('Consoling of obj_level2:\\n', obj_level2); console.log('\\nConsoling of full obj:\\n', obj); // To see that the object is correct 

⋅⋅⋅

我們還可以在上面的代碼段中改編第二個函數,以便它同時適用於get和set,這取決於是否設置了“ value”:

 // We could also adapt the second function for both uses: function obj_path(obj, path, value = null) { var result = obj; var paths = path.split('.'); var len = paths.length; for (var i = 0; i < len - 1; i++) { result = result[paths[i]] || {}; } // Return result if there is no set value if (value === null) return result[paths[len - 1]]; // Set value and return result[paths[len - 1]] = value; return obj; } // Example object var obj = { name0: 'A name', level0: { name1: 'An other name', level1: { level2: { name3: 'Name to be changed', text3: 'Some other text' } } } } // Use of the function obj = obj_path(obj, 'level0.level1.level2.name3', 'Takit Isy'); obj = obj_path(obj, 'level0.level1.level2.new3', 'I'm a new element!'); var obj_level2 = obj_path(obj, 'level0.level1.level2'); // Consoling console.log('Consoling of obj_level2:\\n', obj_level2); console.log('\\nConsoling of full obj:\\n', obj); // To see that the object is correct 

希望能幫助到你。

怎么樣:

 function parse(str) { var arr = str.split('.'); return function(obj) { return arr.reduce((o, i) => o[i], obj); } } let foo = { a: { b: { c: { bar: 0 } } } } let c = parse('abc')(foo); console.log(c.bar); c['bar'] = 1; console.log(foo); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM