如何使用facebook/immutable-js制作自定义不可变类型? [英] How do I make a custom immutable type using facebook/immutable-js?

查看:77
本文介绍了如何使用facebook/immutable-js制作自定义不可变类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个简单的不可变的Interval类型.它具有开始和结束属性.有没有一种直接的方法来利用 immutable-js 库来创建您自己的自定义不可变类型?

I am attempting to make a simple immutable Interval type. It has a start and an end property. Is there a straightforward way to utilize the immutable-js library to create your own custom immutable types?

我当前对Immutable.Map和Immutable.List使用包含模式的尝试效果不佳.例如,difference应该返回一个不可变的Interval列表,但是由于它创建了Interval的新实例,因此它返回的List将不会传递相等性.

My current attempt at using a containment pattern with Immutable.Map and Immutable.List is not working so well. difference, for example, should return an immutable list of Intervals, but because it creates new instances of Interval, the List it returns will not pass equality.

感觉好像我采用了错误的方法,但是我不确定该怎么做.我可以轻松地用Immutable.Map表示数据,但我想在其公共接口中包含difference,而不要包括诸如get和set之类的常规Map方法.也就是说,我希望它是不可变的,但要具有自己的接口类型.

It feels like I am taking the wrong approach, but I'm not sure how. I could easily represent the data with Immutable.Map, but I want to include difference in its public interface, and not include general Map methods like get and set. i.e. I want it to be immutable, yet be its own type with its own interface.

var Immutable = require('immutable')

function Interval(start, end) {
  this.value = Immutable.Map({
    start: start,
    end: end
  })
}

Interval.prototype.start = function () {
  return this.value.get('start')
}

Interval.prototype.end = function () {
  return this.value.get('end')
}

Interval.prototype.equals = function(interval) {
  return this.value.equals(interval.value)
}

Interval.prototype.difference = function (subtrahend) {
  var nonoverlapping = subtrahend.start() > this.end() || subtrahend.end() < this.start()

  return nonoverlapping ? Immutable.List.of(this) :
    Immutable.List.of(
      new Interval(this.start(), subtrahend.start()),
      new Interval(subtrahend.end(), this.end())
    )
    .filter(function(interval) {
      return interval.end() > interval.start()
    })
}

一些测试:

it('should return an empty array for an exact difference', function() {
  var interval = new Interval(80, 90)
  interval.difference(interval)
    .equals(Immutable.List())
    .should.be.true
})

it('should return an array with the same Interval for a missed difference', function() {
  var interval = new Interval(80, 90)
  console.log(interval.difference(new Interval(50, 60)).toJS());
  interval.difference(new Interval(50, 60))
    .equals(Immutable.List.of([
      { value: Immutable.Map({ start: 80, end: 90 }) }
    ]))
    .should.be.true
})

推荐答案

为什么不使用Record类型:

var Interval = Immutable.Record({start: 0, end: 1})

这将为您创建记录类型,分别定义默认值0和1的startend属性.

This creates the record type for you, defining start and end properties with default values of 0 and 1, respectively.

现在要创建Interval的实例,只需执行以下操作:

Now to create instances of Interval, just do:

var newInterval = new Interval() //will have default values above
var newInterval = new Interval({start: 10, end: 30)

请注意,Record类型的实例只是值类型,因此它们应仅包含数据.当然,您可以定义对此数据值进行运算的函数.

Note that instances of Record type are just value types, so they should just contain data. You can, of course, define functions that operate on this data value.

var difference = function (interval1, interval2) {
  var nonoverlapping = interval2.start > interval1.end || interval2.end < interval1.start

  return nonoverlapping ? Immutable.List.of(interval1) :
    Immutable.List([
      new Interval({start: interval1.start, end: interval2.start}),
      new Interval({start: interval2.end, end: interval1.end})
    ])
    .filter(function(interval) {
      return interval.end > interval.start
    });
}

使用Immutable.is(interval1, interval2)

有关记录类型的更多信息: http://facebook.github. io/immutable-js/docs/#/Record

For more information on the record type: http://facebook.github.io/immutable-js/docs/#/Record

这篇关于如何使用facebook/immutable-js制作自定义不可变类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆