如何在仍然使用纯函数的同时更改状态变量,调用self方法和处理窗口函数?

时间:2018-01-24 01:05:05

标签: javascript functional-programming

我目前正在考虑在我的代码中使用大多数纯函数。我意识到了这一点的好处。但是,我想知道更新状态变量,调用模块中定义的方法以及如何处理窗口函数时的最佳实践。

使用下面的示例,我们假设我有一个模块MyModule

  • MyModule.calculate功能是纯粹的,所以不用担心。
  • 然而MyModule.trackSomething函数正在更新MyModule.count以跟踪它,以便在MyModule.assignEventHandlers函数中使用的事件处理程序中使用。这不纯粹,因为它使用外部引用变量。即使我重构计算一个对象并将其作为参数传递给MyModule.trackSomething,我仍然会通过引用改变该值,使其不纯。
  • MyModule.assignEventHandlers函数中,我使用全局窗口对象函数。这使得它不纯,因为我引用了外部函数。在调用函数时,是否应该通过引用传递窗口对象?
  • MyModule.init功能中,我正在调用MyModule.assignEventHandlers功能。我想这也是不纯的,因为MyModule.assignEventHandlers是一个外部参考。

所以我的问题是:处理最后3个要点的最佳方法是什么?

非常感谢任何建议。谢谢!

const MyModule = {
    calculate(a, b) {
        return a + b;
    },

    count: 0,

    trackSomething() {
        MyModule.count += 1;
    },

    assignEventHandlers() {
        // assign event handlers to some DOM elements
        window.document.getElementById('my-ele').addEventListener('click', () => {
            window.alert(MyModule.count);
            MyModule.trackSomething(MyModule.count);
        });
    },

    init() {
        MyModule.assignEventHandlers();
    }
};

1 个答案:

答案 0 :(得分:0)

我认为当我们提出一个解决方案时,不仅仅关注纯粹和不纯的功能,最好还是专注于实用性。可以使用不纯的功能。

这是使用RxJs的另一个版本的实现 - 一个反应性的js lib。也使用ES6类而不是模块。请查看actionaction2。两者都以不同的方式产生相同的结果。

在我看来,action已经足够了。不需要让一切都超级纯净。

class MyClass {
  constructor(elementId) {
    this.ele = document.getElementById(elementId);
    this.click$ = Rx.Observable.fromEvent(this.ele, 'click');
    this.count = new Rx.BehaviorSubject(0);
  }
  
  calculate(a, b) {
     return a + b;
  }
  
  action() {
    window.alert(this.count.getValue());
    const nextVal = this.calculate(this.count.getValue(), 1);
    this.count.next(nextVal);
  }
  
  action2(log, subject, method) {
    log(subject.getValue());
    const nextVal = method(subject.getValue(), 1);
    subject.next(nextVal);
  }
}

const a = new MyClass('my-ele1');
a.click$.subscribe(() => a.action2(window.alert, a.count, a.calculate));

const b = new MyClass('my-ele2');
b.click$.subscribe(() => b.action());
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
<button type="button" id="my-ele1">me1</button>
<br>
<button type="button" id="my-ele2">me2</button>