用es6递归更新对象

时间:2018-03-23 01:04:48

标签: javascript recursion ecmascript-6

我在dataTree中有很多带子项的对象,我想用es6语法递归更新切换值为true并返回更新后的dataTree

对象看起来像这样

{
    name: "Misc", 
    toggled: true,
    children: [{
        name: "Apple",
        toggled:false
        children: [{
            name: "banana",
            toggled:false
        }]
    }]
}

等...

任何想法,谢谢

3 个答案:

答案 0 :(得分:1)

为您的{ name, toggled, children }类型创建一个模块 - 我们称之为Node

const Node =
  { make : (name = "", toggled = false, children = []) =>
      ({ name, toggled, children })

  , toggle : (node) =>
      Node.make (node.name, !node.toggled, node.children)

  , toggleAll : (node) =>
      Node.make (node.name, !node.toggled, node.children.map (Node.toggleAll))
  }

请注意,toggletoggleAll不会改变原始输入 - 而是始终创建新节点

const n =
  Node.make ("foo", true)

console.log (n, Node.toggle (n), n)
// { name: 'foo', toggled: true, children: [] }
// { name: 'foo', toggled: false, children: [] }
// { name: 'foo', toggled: true, children: [] }

我们可以直接在data上使用此功能来切换所有toggled字段

const data = 
  { name : "Misc"
  , toggled : true
  , children :
    [ { name : "Apple"
      , toggled : false
      , children :
        [ { name : "banana"
          , toggled : false
          , children : []
          }
        ]
      }
    ]
  }

console.log (Node.toggleAll (data))

// { name : "Misc"
// , toggled : false              <--- toggled
// , children :
//   [ { name : "Apple"
//     , toggled : true           <--- toggled
//     , children :
//       [ { name : "banana"
//         , toggled : true       <--- toggled
//         , children : []
//         }
//       ]
//     }
//   ]
// }

但是,不应使用对象文字语法编写数据,而应使用模块

const data =
  Node.make ( "Misc"
            , true
            , [ Node.make ( "Apple"
                          , false
                          , [ Node.make ("banana", false) ]
                          )
              ]
            )

console.log (Node.toggleAll (data))
// same output
  

我想以递归方式将切换值更新为true ...

如果要将所有toggled设置为特定值,可以为其编写特定函数

const Node =
  { ...
  , toggleAllOn : (node) =>
      Node.make (node.name, true, node.children.map (Node.toggleAllOn))
  }

或者,我们可以使用参数

使原始Node.toggleNode.toggleAll更灵活,而不是制作大量特定功能
const TOGGLE =
  Symbol ()

const Node =
  { make : (name = "", toggled = false, children = []) =>
      ({ name, toggled, children })

  , toggle : (node, value = TOGGLE) =>
      Node.make ( node.name
                , value === TOGGLE ? !node.toggled : Boolean (value)
                , node.children
                )

  , toggleAll : (node, value = TOGGLE) =>
      Node.make ( node.name
                , value === TOGGLE ? !node.toggled : Boolean (value)
                , node.children.map (n => Node.toggleAll (n, value))
                )
  }

现在我们可以使用n 切换节点Node.toggle (n)使用Node.toggle (n, true)Node.toggle (n, false)

设置特定的切换状态
const n =
  Node.make ("foo", true)

console.log (n, Node.toggle (n, true), Node.toggle (n), n)
// { name: 'foo', toggled: true, children: [] }     <--- original
// { name: 'foo', toggled: true, children: [] }     <--- already true; no change
// { name: 'foo', toggled: false, children: [] }    <--- toggled
// { name: 'foo', toggled: true, children: [] }     <--- immutable

当然它也适用于Node.toggleAll (n, true)

const allTrue =
  Node.toggleAll (data, true)

console.log (allTrue)
// { name : "Misc"
// , toggled : true              <--- same value
// , children :
//   [ { name : "Apple"
//     , toggled : true          <--- set to true
//     , children :
//       [ { name : "banana"
//         , toggled : true      <--- set to true
//         , children : []
//         }
//       ]
//     }
//   ]
// }

程序演示

&#13;
&#13;
const TOGGLE =
  Symbol ()

const Node =
  { make : (name = "", toggled = false, children = []) =>
      ({ name, toggled, children })

  , toggle : (node, value = TOGGLE) =>
      Node.make ( node.name
                , value === TOGGLE ? !node.toggled : value
                , node.children
                )

  , toggleAll : (node, value = TOGGLE) =>
      Node.make ( node.name
                , value === TOGGLE ? !node.toggled : value
                , node.children.map (n => Node.toggleAll (n, value))
                )
  }
      
const data =
  Node.make ( "Misc"
            , true
            , [ Node.make ( "Apple"
                          , false
                          , [ Node.make ("banana", false) ]
                          )
              ]
            )

// display original
console.log ('original', data)

// only toggle this node
console.log ('toggle', Node.toggle (data))

// toggle this node and all children
console.log ('toggleAll', Node.toggleAll (data))

// set this node and all children to true
console.log ('toggleAll true', Node.toggleAll (data, true))

// check original data is not mutated (OK!)
console.log ('original', data)
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我不确定这是不是你想要的,但我试过了。

var obj = {
    name: "Misc", 
    toggled: true,
    children: [{
        name: "Apple",
        toggled:false,
        children: [{
            name: "banana",
            toggled:false
        }]
    }]
};

var toggleToTrue = function(obj){

    if (!obj) { return false; }
    obj.toggled = true;

    if (!obj.children) { return false; }    
    var childs = obj.children;    
    for (var i in childs){
        toggleToTrue(childs[i]);
    }

};

toggleToTrue(obj);

console.log(obj);

答案 2 :(得分:0)

您可以将以下内容用于不会改变原始对象的递归解决方案,不会为没有这些属性的对象添加属性(如果对象添加toggled它没有它,并且可以由调用者配置来改变某些行为:

&#13;
&#13;
var obj = {
  name: "Misc", 
  toggled: true,
  children: [{
      name: "Apple",
      toggled:false,
      children: [{
          name: "banana",
          toggled:false
      }]
  }]
};

const changeProp = (shouldSet,set,doRecursive,rec) => calcValue => (obj) => {
  const toggle = o => {
    if (shouldSet(o)) {
      return set({ ...o },calcValue(o));
    }
    return o;
  };
  return (!doRecursive(obj))
    ? toggle(obj)
    : rec(toggle(obj),changeProp(shouldSet,set,doRecursive,rec)(calcValue))
};

const hasChild = o=>(o.hasOwnProperty("children") && Array.isArray(o.children));
const setRecursive = (o,rec)=>({ 
  ...o,
  children:o.children.map(rec)
});

//set toggled to true
console.log(
  changeProp(
    o=>(typeof o.toggled === "boolean"),//should set function
    (o,value)=>{o.toggled=value;return o; },//set function
    hasChild,//do recursive?
    setRecursive//recursively set
  )(()=>true)//calculate value based on object (value is always true)
  (obj)
);
//upper case name
console.log(
  changeProp(
    o=>(typeof o.name === "string"),//should set function
    (o,value)=>{o.name=value;return o; },//set function
    hasChild,//do recursive?
    setRecursive//recursively set
  )((o)=>o.name.toUpperCase())//calculate value based on object (name to uppercase)
  (obj)
);
&#13;
&#13;
&#13;