如果通过引用传递对象,我如何在函数式编程中处理它们

时间:2017-12-31 06:13:26

标签: javascript functional-programming javascript-objects

过去几天我一直在玩一些代码而且我正在尝试更多地进行函数式编程,但我正处于障碍之中。我不明白如何处理一个物体。基本上我有一个对象,我想添加键值对。我理解在函数编程中你不能重新分配你只需用添加的键值对创建一个新对象。我正在考虑将对象放在某种类型的容器中,比如' Box'

const Box = x =>
({
  map: f => Box(f(x)),
  fold: f => f(x),
})

然后使用' Box'并添加我的所有键值对,如

const formData = obj =>
  Box(obj)
  .map(s => s.key1 = document.getElementById("value1").value)
  .map(s => s.key2 = document.getElementById("value2").value)
  .fold(s => s)

var emptyObj = {};
const test = formData(emptyObj);

我注意到' emptyObj'将同时具有两个键值对但是“测试”#39;将不会。我知道我要么完全错过它,要么就是不理解这个过程。我一直在看

https://egghead.io/courses/professor-frisby-introduces-composable-functional-javascript

并且它与电子书一起很棒但是必须有一些我缺少的东西。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

问题是你的map回调函数返回字符串(赋值的结果是右边),而不是它们分配给它们的属性的对象。你需要写

Box(obj)
.map(s => (s.key1 = document.getElementById("value1").value, s))
.map(s => (s.key2 = document.getElementById("value2").value, s))
.fold(s => s)

获取test === emptyObject(并且同时拥有两个属性)。

那就是说,我不明白这个" Box"很好。如果你刚刚写完

会更简单
const formData = () => ({
  key1: document.getElementById("value1").value,
  key2: document.getElementById("value2").value,
});

答案 1 :(得分:1)

我认为你需要做这样的事情:

const formData = obj =>
  Box(obj)
   .map(s => ({ ...s, key: document.getElementById("value1").value }) )
   .map(s => ({ ...s, key2: document.getElementById("value2").value } )) 
   .fold(s => s)

请注意,我不会使用mapfold而是使用monadic名称thenbind

答案 2 :(得分:0)

  

我理解在功能编程中你不能重新分配你   添加了键值对的新对象。

不变性并不完全等同于函数式编程,但是我希望从这个语句中得到你期望的结果(你在帖子中没有明确说明!)是emptyObj保持原始的空对象,并将test作为具有key1key2属性的单独对象。

问题是你不应该为此使用对象。不是因为他们反对功能编程,而是因为对象不是真正的词典,并且没有简单的工具来做这类事情。您想要使用地图。地图被设计为字典,更重要的是,它是迭代器,允许一些速记和减少认知负荷。

const Box=(x)=>({
    map: (key,value)=>Box((new Map(x).set(key,value))),
    clear: (key,value)=>Box((copy=>(copy.delete(key),copy))(new Map(x))
    ),
    fold: f=>f(new Map(x)), // EDITED to prevent leaking the original map
})

const formData=obj=>(
    Box(obj)
    .map('key1',document.getElementById("value1").value)
    .map('key2',document.getElementById("value2").value)
    .fold(s=>s)
)
const clearData=obj=>(
    Box(obj)
    .clear('key1')
    .clear('key2')
    .fold(s=>s)
)

const emptyObj=new Map()
const test1=formData(emptyObj)
const test2=clearData(test1)

console.log(emptyObj) // empty
console.log(test1) // both keys
console.log(test2) // empty again

我添加了不可变clear数据以及map数据的功能,以显示它是多么容易。我在clear方法中使用了一个奇怪的构造,因为Map.prototype.delete返回成功布尔值而不是Map,所以我使用了逗号运算符。这些从左到右评估并返回最后一个值。

如果你想进入不可变的而不是严格的功能,那么有可用于Javascript的不可变类库可以提供不可变的映射,或者很容易将其子类化。

修改

OP已经提到需要在JSON互通的对象中执行此操作。可以使用辅助函数将Map转换为JSON:

让map = new Map([[' key1',' value1'],[' key2',' value2']] )

const mapToJson=map=>(
    '{'+
    [...map].map(([key,value])=>(
        '"'+key+'":'+(value===undefined ? 'null' : JSON.stringify(value)))
    ).join(',')+
    '}'
)

console.log(mapToJson(map)) // {"key1":"value1","key2":"value2"}

我必须添加undefined的特定检查,因为JSON.stringify(undefined)=='undefined',但JSON规范无法识别undefined并改为使用null

这假定字符串键,但地图可以使用任何键作为键。您可以添加错误检查,或者只是假设您只传递带字符串键的Map。