我有一个带有设置的JSON对象,类似于:
var settings = {
tab1: {
active: true,
selectOrder: 1,
selected: false
},
tab2: {
active: true,
selectOrder: 2,
selected: false
},
tab3: {
active: false,
selectOrder: 0,
selected: false
}
};
现在,我的目标是设置选择的'财产是真实的'对于具有最低选择订单的活动元素'在这个例子中,我应该设置选择'对于' tab1' element(' tab3' selectedOrder为0但未激活)。
背后的原因是根据优先级选择第一个活动选项卡(selectOrder)。
我的解决方案是:
function selectFirstActiveTab(visibilitySettings) {
var selected = 1000;
var answer = jQuery.extend({}, visibilitySettings);
Object.keys(answer).forEach((key) => {
if (answer[key].active && answer[key].selectOrder <= selected) {
selected = answer[key].selectOrder;
}
});
Object.keys(answer).forEach((key) => {
answer[key].selected = (answer[key].selectOrder === selected) ? true : false;
});
return answer;
};
虽然这个解决方案正在运行,但它似乎很糟糕。
我的问题是:
是否有更好的&#34;功能性编程&#34;方法呢? (例如,使用map / reduce等)
我觉得我的设置对象结构不合理。也许我应该选择一个对象数组而不是这个JSON?选择像这样的JSON的原因是为了更简单地绑定到我的模板(类似于&#34; {{settins.tab1.selected}}&#34; - 在我的html中查找它更简单)。这里有什么更好的方法?
答案 0 :(得分:2)
Object
上的map和reduce,您可以使用Underscore:function selectFirstActiveTab(visibilitySettings) {
// Clone input, with selected set to false.
var answer = _.mapObject(visibilitySettings, (item, key) => {
return {active: item.active, selectOrder: item.selectOrder, selected: false};
});
// Find the min among all value.
var minObj = _.reduce(answer, (min, item) => {
return (item.active && item.selectOrder < min.selectOrder) ? item : min;
}, {active: true, selectOrder: Number.MAX_SAFE_INTEGER});
// Set min to selected.
minObj.selected = true;
return answer;
};
或vanilla javascript:
function selectFirstActiveTab(visibilitySettings) {
var keys = Object.keys(visibilitySettings);
// Create a cloned obj, like map
var answer = {};
keys.forEach((key) => {
var cloneTarget = visibilitySettings[key];
answer[key] = {
active: cloneTarget.active,
selectOrder: cloneTarget.selectOrder,
selected: false
};
});
// Convert key => value map to an array of value, then reduce it to find min.
var minimun = keys.map((key) => answer[key]).reduce((min, item) => {
return (item.active && item.selectOrder < min.selectOrder) ? item : min;
}, {active: true, selectOrder: Number.MAX_SAFE_INTEGER});
// Set min to selected.
minimun.selected = true;
return answer;
};
JSON
,它只是一个带有一些键值映射的普通Object
,我们将它用作Map
。如果输入是如下数组,则可能更容易应用上面的逻辑:
var settings = [
{
name: 'tab1',
active: true,
selectOrder: 1,
selected: false
},
{
name: 'tab2',
active: true,
selectOrder: 2,
selected: false
},
{
name: 'tab3',
active: false,
selectOrder: 0,
selected: false
}
];
由于vanilla javascript支持array
上的reduce / map。但是,像lodash,underscore这样的许多库只会使对象上的reduce / map可用。您可以
只需选择最适合您需求的那个(因为那里有很多类似的库,可以让你通过对象进行映射/缩小)。
答案 1 :(得分:2)
使用lodash,您可以编写以下内容:
import { chain, transform, extend } from 'lodash';
transformObj = (obj) => chain(settings)
.map((obj, key)=> ({ key, obj }))
.select(({ obj: { active }})=> active)
.min(({ obj: { selectOrder }})=> selectOrder)
.thru(({ key })=> transform(settings, (memo, val, _key) => {
memo[_key] = extend({}, val, {
selected: (_key == key)
})
}, {})
)
.value()
> transformObj(settings)
{ tab1: { active: true, selectOrder: 1, selected: true },
tab2: { active: true, selectOrder: 2, selected: false },
tab3: { active: false, selectOrder: 0, selected: false } }
以上假定ES6 imports,arrow functions和参数destructuring的可用性。否则,您可以使用babel。
这更具功能性,因为transformObj
是引用透明的&amp;不会改变它的论点。
答案 2 :(得分:0)
试试这个:
tmp = 0;
_tab = false;
for ( tab in settings ){
if((settings[tab].active)){
if(!tmp){
tmp = settings[tab].selectOrder;
_tab = tab;
}else if(settings[tab].selectOrder < tmp){
_tab = tab;
}
};
}
settings[_tab].selected = true;