【问题标题】:RequireJS, Pub/Sub. I can't access view instance from its own method without a bad workaround.RequireJS,发布/订阅。如果没有一个不好的解决方法,我无法从它自己的方法访问视图实例。
【发布时间】:2013-10-12 10:48:07
【问题描述】:

到目前为止,我主要从事 Java 项目,并试图了解 Javascript 和模块化。我真的很喜欢 Java 中经常使用的观察者模式,因此我实现了一个 Pub/Sub 模块,它可以用来监听模型模块的变化。

这是我的测试应用程序的组件。

TestModel.js

define("testModel", ["observable"],
  function (observable) {

    var TestModel = (function () {
      function TestModel() {
        this.name = "name";
      }

      TestModel.prototype.setName = function (name) {
        this.name = name;
        this.publish(name);
      };

      observable.makeObservable(TestModel.prototype);
      return TestModel;
    })();

    return {
      TestModel: TestModel
    };
  });

TestView.js

define("testView", [],
  function () {

    var TestView = (function () {
      function TestView() {
        this.string = "my Name is ";
      }

      TestView.prototype.talk = function (test, self) {
        console.log(self.string + test);
        //HERE this.string IS UNDEFINED !!!!, because TestModel called talk()
        console.log(this.string + test);
      }

      return TestView;
    })();
    return {
      TestView: TestView
    };
  });

testapp.js

define("testapp", ["testModel", "testView"], function (testModel, testView) {

  var initialize = function () {
    var model = new testModel.TestModel();
    var view = new testView.TestView();

    model.addSubscriber(view.talk, view);
    model.setName("Frank");
  }
  return {
    initialize: initialize
  };
});

而 observable 模块只是通过调用向模型添加了 3 个通用函数 makeObservable()

observable.js

define("observable", [],
  function () {
    /**
     * Observable Object, holds 3 geneneric functions.
     * @type {{addSubscriber: Function, removeSubscriber: Function, publish: Function}}
     */
    var Observable = {

      addSubscriber: function (callback, subscriber) {
        this.callbacks[this.callbacks.length] = callback;
        this.subscribers[this.subscribers.length] = subscriber;
      },
      removeSubscriber: function (callback) {
        for (var i = 0; i < this.callbacks.length; i++) {
          if (this.callbacks[i] === callback) {
            delete(this.callbacks[i]);
            delete(this.subscribers[i]);
          }
        }
      },
      publish: function (what) {
        for (var i = 0; i < this.callbacks.length; i++) {
          if (typeof this.callbacks[i] === 'function') {
            this.callbacks[i](what, this.subscribers[i]);
          }
        }
      }
    }

    /**
     * Function takes another function Module and adds the 3
     * functions from Observable to it.
     *
     * @param o
     */
    var makeObservable = function (o) {
      // turns an object into a publisher
      for (var i in Observable) {
        o[i] = Observable[i];
        o.callbacks = [];
        o.subscribers = [];
      }
    }

    return {
      makeObservable: makeObservable
    };
  });

现在我的问题。我真的不想在模型中保存订阅者列表,这在某种程度上违反了松散耦合的原则。但是如果我只在subscribe()方法中给TestModel添加一个回调函数,我将无法访问TestView中的this.string变量。因为this 指向调用了talk() 方法的TestModel。我的解决方法是 self,这导致模型中需要订阅者列表。

我还尝试在 RequireJS 调用和返回的 TestView 函数中初始化 TestView 函数之外的 self 变量。但是这个函数只被调用一次,因此该变量在 Java 中就像一个静态变量,并且在 TestView 的每个实例中都不是唯一的。

是否有可能在talk() 函数中获得一个self/this 变量来访问字符串,而无需像现在这样由TestModel 处理它?

【问题讨论】:

  • 使用model.addSubscriber(view.talk.bind(view)) 然后回调将隐式地将视图绑定到回调的this 引用。否则,您可以执行model.addSubscriber(view, "talk") 之类的操作并让Observable 调用this.subscribers[i][this.methodNames[i]].call(this.subscribers[i], what)
  • model.addSubscriber(view.talk.bind(view)) 似乎正是我想要的。非常感谢你。是否有可能支持您的评论?将鼠标悬停在它上面时应该会出现一个箭头,但我看不到一个。
  • 好的,我会添加作为答案,也许问题可以这样结束。

标签: javascript requirejs this publish-subscribe


【解决方案1】:

您可以使用Function.bind 创建一个回调,将view 绑定到它的this 引用:

model.addSubscriber(view.talk.bind(view));

或者,您可以将订阅者和方法名称传递给Observable(您现在保存订阅者和方法名称,而不是订阅者和回调):

model.addSubscriber(view, "talk");

Observable 将调用此方法,如下所示:

for (var i = 0; i < this.subscribers.length; i++) {
    var sub = this.subscribers[i];
    var methName = this.methodNames[i];
    // invoke the method of sub called methName,
    // and pass sub as the this parameter,
    // and what as the single method parameter.
    sub[methName].call(sub, what);
}

【讨论】:

    猜你喜欢
    • 2014-09-24
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多