问题
问题 1
在尝试将 int 添加在一起时,我不能只做上面所做的事情。
嗯,这就是重点。在反应式编程中,您不想强制地将两个数字相加,而是希望根据其他数字定义新数字。因此,即使或发生变化, 也总是等于 :c = a + b
相c
对于和是反应性的。a + b
a
b
c
a
b
var a = new BehaviorSubject(3);
var b = new BehaviorSubject(1);
var c = Rx.Observable.combineLatest(a, b, function(vals) {
return vals[0] + vals[1];
});
问题2
我想知道如何准确地实施第二高评分答案中给出的示例。
haskell 中最简单的答案列表和高阶函数。
回答你不希望函数式反应式编程与你在命令式编程中学到的一切背道而驰,如果你想做纯函数式反应式编程,你将不得不重新学习如何做事。如果你不这样做,你最终会制作各种依赖跟踪库,比如KnockoutJS ,如果你使用 FRP 开始,你可以用RxJS-Splash之类的东西在几百行中做同样的事情. (注意 Splash 如何基于 Rx,这是可重用的代码,而 Knockout 是纯粹的实现特定代码)。
FRP 有事件和时间的概念,而依赖跟踪只有值和变化的概念。功能响应式代码与命令式代码一样长。它不是“建立在命令式代码之上”。(是的,它仍然编译为汇编......不是重点),它在概念上根本不同。
例子
使用 Microsoft 的 JavaScript 响应式扩展 ( RxJS )
请记住,Rx 现在可以在很多语言中使用,包括原生C++。
示例的直接端口
var moves = $(document).onAsObservable('mousemove')
.map(function(e) {
return {
x: e.pageX,
y: e.pageY
};
});
var xs = moves.map(function(move) { return move.x; });
var ys = moves.map(function(move) { return move.y; });
var minXs = xs.map(function(x) { return x - 16; });
var minYs = ys.map(function(y) { return y - 16; });
var maxYs = xs.map(function(x) { return x + 16; });
var maxYs = ys.map(function(y) { return y + 16; });
var boundingRect = Rx.Observable.combineLatest(minXs, minYs, maxXs, maxYs)
.map(function(vals) {
var minX = vals[0];
var minY = vals[1];
var maxX = vals[2];
var maxY = vals[3];
return new Rectangle(minX, minY, maxX, maxY);
});
简化端口
由于矩形仅根据一个相关值(或事件)定义,因此您可以将其简化为以下内容:
var boundingRect = $(document).onAsObservable('mousemove')
.map(function(e) {
var x = e.pageX;
var y = e.pageY;
return new Rectangle(x - 16, y - 16, x + 16, y + 16);
});
使用它
此时,您可以使用它来组成其他可观察的序列(随时间变化的值)。
var area = boundingRect.map(function(rect) {
return rect.getSize();
});
或者直接订阅。
boundingRect.subscribe(function (rect) {
// perform some action with the rect each time it changes.
console.log(rect);
});
但这只是在它改变的时候!
如果我们一订阅就想要最新的值,而不是等待矩形再次改变怎么办?嗯,这就是BehaviorSubject
s 进来的地方。
var rects = new Rx.BehaviorSubject(new Rectangle(-1, -1, 1, 1));
rects.subscribe(function(rect) {
// this would happen twice in this example.
// Once for the initial value (above), and once when it is changed later (below).
console.log(rect);
});
rects.onNext(new Rectangle(-1, -1, 1, 1));
但这不是原始的 observable,而且它不是很实用......
以下是如何使用一些内置功能对原始 observable 执行相同的操作,以将 Observable 更改为类似于 BehaviorSubject 的行为...
var rectsAndDefault = rects.startWith(new Rectangle()); // just give it an initial value
rectsAndDefault.subscribe(function(rect) {
console.log(rect); // happens once for the "startWith" rectangle, and then again for all subsequent changes
})
同样,FRP 是不同的。这是很好的不同,但这是一项艰巨的学习任务。当它开始让你大吃一惊时,你就会知道你已经开始明白了。