如何使用 facebook/immutable-js 创建自定义不可变类型?
How do I make a custom immutable type using facebook/immutable-js?
我正在尝试创建一个简单的不可变 Interval 类型。它有开始和结束 属性。有没有直接的方法来利用 immutable-js 库来创建您自己的自定义不可变类型?
我目前尝试将包含模式与 Immutable.Map 和 Immutable.List 一起使用,但效果不佳。 difference
,例如,应该 return 一个不可变的 Intervals 列表,但是因为它创建了新的 Interval 实例,所以 List it returns 不会传递相等性。
感觉我采取了错误的方法,但我不确定如何。我可以很容易地用 Immutable.Map
表示数据,但我想在其 public 接口中包含 difference
,而不包含一般的 Map
方法,如 get 和 set。即我希望它是不可变的,但它是具有自己的接口的自己的类型。
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})
这将为您创建记录类型,定义 start
和 end
属性,默认值分别为 0 和 1。
现在要创建 Interval
的实例,只需执行以下操作:
var newInterval = new Interval() //will have default values above
var newInterval = new Interval({start: 10, end: 30)
请注意,Record
类型的实例只是值类型,因此它们应该只包含数据。当然,您可以定义对该数据值进行操作的函数。
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
您可以使用 "extendable-immutable" library.
那就简单了:
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');
}
//...
}
如果您像我一样在字段上选择方法(例如开始、结束),我不建议使用 Record。如果您使用 Record 实现它,您将拥有自动公开的字段。
您可能想要使用 _value
字段创建您的记录自定义 class,而不是公开 value
字段,但这并不总是可行的。参见:
实施方法valueOf
。
例如:
Interval.prototype.valueOf = function() {
return Map({ class: Interval, value: this.value });
}
关于测试:
Immutable.is(new Interval(80, 90), new Interval(80, 90)); // true
另一种选择是通过实现方法 equals
和 hashCode
将 class 转换为 ValueObject(使用函数 Immutable.is
和 Immutable.hash
用于实施)。
我正在尝试创建一个简单的不可变 Interval 类型。它有开始和结束 属性。有没有直接的方法来利用 immutable-js 库来创建您自己的自定义不可变类型?
我目前尝试将包含模式与 Immutable.Map 和 Immutable.List 一起使用,但效果不佳。 difference
,例如,应该 return 一个不可变的 Intervals 列表,但是因为它创建了新的 Interval 实例,所以 List it returns 不会传递相等性。
感觉我采取了错误的方法,但我不确定如何。我可以很容易地用 Immutable.Map
表示数据,但我想在其 public 接口中包含 difference
,而不包含一般的 Map
方法,如 get 和 set。即我希望它是不可变的,但它是具有自己的接口的自己的类型。
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})
这将为您创建记录类型,定义 start
和 end
属性,默认值分别为 0 和 1。
现在要创建 Interval
的实例,只需执行以下操作:
var newInterval = new Interval() //will have default values above
var newInterval = new Interval({start: 10, end: 30)
请注意,Record
类型的实例只是值类型,因此它们应该只包含数据。当然,您可以定义对该数据值进行操作的函数。
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
您可以使用 "extendable-immutable" library.
那就简单了:
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');
}
//...
}
如果您像我一样在字段上选择方法(例如开始、结束),我不建议使用 Record。如果您使用 Record 实现它,您将拥有自动公开的字段。
您可能想要使用 _value
字段创建您的记录自定义 class,而不是公开 value
字段,但这并不总是可行的。参见:
实施方法valueOf
。
例如:
Interval.prototype.valueOf = function() {
return Map({ class: Interval, value: this.value });
}
关于测试:
Immutable.is(new Interval(80, 90), new Interval(80, 90)); // true
另一种选择是通过实现方法 equals
和 hashCode
将 class 转换为 ValueObject(使用函数 Immutable.is
和 Immutable.hash
用于实施)。