[英]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 {
更換零件:
您可以嘗試這樣的操作,如果路徑不存在,則值為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.