Immutable.fromJS() 不深

Immutable.fromJS() is not deep

Immutable.fromJS的描述是:

Deeply converts plain JS objects and arrays to Immutable Maps and Lists.

但这是错误的。我有一个具有以下结构的对象。大写的项目是 ES6 类.

Foo
  prop1
  prop2
  bars
    Bar
      prop1
      prop2
    Bar
      prop1
      prop2
  bazes
    Baz
      prop1
      prop2
      bars
        Bar
          prop1
          prop2
        Bar
          prop1
          prop2
    Baz
      prop1
      prop2
      bars
        Bar
          prop1
          prop2
        Bar
          prop1
          prop2

Immutable.fromJS(foo) 的结果是一个地图。数组 barsbazesList。但是,这些列表中的每个元素仍然是普通 (ES6) 对象。每个Baz的bars属性是数组,不是列表

是我做错了什么,还是文档不正确?

也许 ES6 对象不支持深度特征?如果是这样,我怎样才能使我的对象深度不可变?

更新:

这有效但感觉有点恶心:Immutable.fromJS(JSON.parse(JSON.stringify(foo)))

docs for fromJS 中的第一句话是:

Deeply converts plain JS objects and arrays to Immutable Maps and Lists.

如果 Foo、Bar 和 Baz 是 ES6 classes 那么它们既不是普通的 JS 对象也不是数组——它们是 class 的实例。所以,不,文档没有错。

顺便说一句,如果 Immutable.fromJS 自动将它遇到的任何对象转换为普通 JS 对象,正如您似乎所期望的那样,这对大多数用户来说将是非常令人惊讶的行为,而且根本不会可取。

但由于这是您想要的行为,您会很高兴知道 Immutable wiki 有 a section on this exact topic,我将在此处复制以供后代使用:

Here is an example which will convert any Object, including exotic Objects, to Immutable.Map:

function fromJSGreedy(js) {
  return typeof js !== 'object' || js === null ? js :
    Array.isArray(js) ? 
      Immutable.Seq(js).map(fromJSGreedy).toList() :
      Immutable.Seq(js).map(fromJSGreedy).toMap();
}

这很简单。而且,事实上,它完全按照承诺工作,正如您在 运行 下面的代码片段中看到的那样。

class Foo {
  constructor(name, ...children) {
    this.name = name;
    this.children = children;
  }
}

class Bar extends Foo {}
class Baz extends Foo {}

const myBar = new Bar("myBar", new Baz("myBaz1"), new Baz("myBaz2"));
const myFoo = new Foo("myFoo", myBar);

function fromJSGreedy(js) {
  return typeof js !== 'object' || js === null ? js :
    Array.isArray(js) ? 
      Immutable.Seq(js).map(fromJSGreedy).toList() :
      Immutable.Seq(js).map(fromJSGreedy).toMap();
}

console.log(fromJSGreedy(myFoo).toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>

此外,我必须检查 Date 类型,因为此函数将我的日期转换为非日期对象。这个函数使用了 typescript 和 lodash,但我相信你可以相应地改变它

export function myFromJS(js: any): any {
  return typeof js !== 'object' || js === null || (_.isDate(js)) ? js :
    Array.isArray(js) ?
      Immutable.Seq(js).map(myFromJS).toList() :
      Immutable.Seq(js).map(myFromJS).toMap();
}