问题
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?
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.
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()
})
}
Some tests:
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
})
回答1:
Why not use Record
type:
var Interval = Immutable.Record({start: 0, end: 1})
This creates the record type for you, defining start
and end
properties with default values of 0 and 1, respectively.
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)
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
});
}
Equality you get for free, using Immutable.is(interval1, interval2)
For more information on the record type: http://facebook.github.io/immutable-js/docs/#/Record
回答2:
You can use "extendable-immutable" library.
Then it is easy:
const {Map} = require('extendable-immutable');
class Interval extends Map {
constructor(start, end) {
super({
value: new Map({start: start, end: end})
});
}
start() {
return this.get('value').get('start');
}
end() {
return this.get('value').get('end');
}
//...
}
I do not recommend Record if you choose methods (such as start, end) over fields like me. If you implement it with Record you will have field(s) that are exposed automatically.
Instead of exposing a value
field, you may want to create your Record custom class with _value
field, however it is not always possible. See:
https://github.com/facebook/immutable-js/issues/970
回答3:
Implement the method valueOf
.
For example:
Interval.prototype.valueOf = function() {
return Map({ class: Interval, value: this.value });
}
and on the tests:
Immutable.is(new Interval(80, 90), new Interval(80, 90)); // true
Another option is to convert the class to a ValueObject by implementing the methods equals
and hashCode
(Use the functions Immutable.is
and Immutable.hash
for the implementation).
来源:https://stackoverflow.com/questions/31816069/how-do-i-make-a-custom-immutable-type-using-facebook-immutable-js