代码之家  ›  专栏  ›  技术社区  ›  Dmitry Volkov

在JavaScript中编写类C的扩展以实现可观察的淘汰

  •  1
  • Dmitry Volkov  · 技术社区  · 8 年前

    考虑以下代码:

    if (countriesLookup()) {
        countriesLookup().fill(initialData.Countries);
    } else {
        const subscription = countriesLookup.subscribe(function (lookup) {
            lookup.fill(initialData.Countries);
            subscription.dispose();
        });
    }
    

    这是我的ko。可观察到 countriesLookup . 如果在数据初始化时组件本身尚未初始化( countriesLookup() == undefined ),我订阅该可观察对象,当它最终获得组件时,我使用初始数据执行初始化,并取消订阅。

    让我们暂时忘记这种方法会导致回调地狱等,并考虑可能的方法来降低这种情况。

    我想写一些像observable的C#扩展这样的东西,就像使用中的一样:

    countriesLookup.initialize(x => x.fill(initialData.Countries));
    

    实现应该是这样的:

    ko.observable.prototype.initialize = function(initializeFunc) {
        const currentValue = ???
        if (currentValue()) {
            initializeFunc(currentValue());
        } else {
            const subscription = currentValue.subscribe(function (lookup) {
                initializeFunc(lookup);
                subscription.dispose();
            });
        }
    }
    

    显然,这是行不通的,特别是因为我不确定这是否能够在“扩展”方法中得到当前的可观测值。

    我目前正在考虑C#编程,在这方面我有点精通,并且非常希望得到一些关于如何编写此类扩展的建议。


    也许我应该多解释一下我的问题。我知道当前值可以使用 this 在添加到原型的方法中,问题在于observable返回一个函数。

    例如,此

    String.prototype.SayHi = function SayHi() {
        return "Hi " + this + "!";
    };
    "blah".SayHi();      //return "Hi blah!"
    

    很好,但这个

    ko.observable.prototype.SayHi = function SayHi() {
        return "Hi " + this + "!";
    };
    var a = ko.observable("blah")
    a.SayHi();
    

    失败,出现以下错误:

    VM543:1 Uncaught TypeError: a.SayHi is not a function at <anonymous>:1:3

    我希望它补充了一些澄清。

    1 回复  |  直到 8 年前
        1
  •  2
  •   Adrian    8 年前

    如果我明白你的意思,你的目标是为可观察对象添加一个自定义函数。
    在这种情况下,您应该使用 fn 而不是 prototype .
    查看此链接: http://knockoutjs.com/documentation/fn.html

    我不确定这是否可以在“扩展”方法中获得可观察的当前值

    你可以用这个方法得到你的可观测值的当前值,因此你上面的例子非常接近你想要的。

    ko.observable.fn.initialize = function(initializeFunc) {
      const currentValue = this;
      if (currentValue()) {
        initializeFunc(currentValue());
      } else {
        const subscription = currentValue.subscribe(function(lookup) {
          initializeFunc(lookup);
          subscription.dispose();
        });
      }
      return this;
    }
    
    var ViewModel = function() {
      this.data = ko.observable().initialize(x => console.log("Value changed to: " + x));
      this.data("100");
    };
    
    ko.applyBindings(new ViewModel());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

    ================================
    注: 有一个关于原因的讨论 fn公司 使用而不是 原型 有人指出 extenders 出于某些性能原因。
    请在此处阅读: https://github.com/knockout/knockout/issues/979

    推荐文章