【问题标题】:Knockout ViewModel base class, Javascript inheritanceKnockout ViewModel 基类,Javascript 继承
【发布时间】:2013-05-10 07:20:39
【问题描述】:

我最近在很多项目中都使用了 Knockout.js,并且我正在编写很多重复的代码。我希望能够定义一个BaseViewModel 类并让我的特定于页面的 ViewModel 继承自它。我对如何做到这一点感到有点困惑是 Javascript。这是我的基本BaseViewModel

(function (ko, undefined) {
    ko.BaseViewModel = function () {
        var self = this;
        self.items = ko.observable([]);
        self.newItem = {};
        self.dirtyItems = ko.computed(function () {
            return self.items().filter(function (item) {
                return item.dirtyFlag.isDirty();
            });
        });
        self.isDirty = ko.computed(function () {
            return self.dirtyItems().length > 0;
        });
        self.load = function () { }
    };
}(ko));

我希望能够在BaseViewModel 中列出诸如load 之类的方法的签名,然后在继承的ViewModel 中对其进行定义。这有可能吗?我在网上找到了一些解决方案,但它们都依赖于定义函数/类来使继承工作。

【问题讨论】:

  • 为什么要将undefined 传递给函数?
  • 嗯,以前从未见过。我也从未遇到过不这样做会导致错误的情况,他也没有解释这种情况是什么。
  • 如果您正在编写供他人使用的代码,这是一种防御技术。可以重新定义undefined 符号。声明函数参数undefined,然后不为该参数传递任何值是一种捕获实际undefined 值的技术,即使有人重新定义了该符号。碰巧的是,它还可以让您的 JS 最小化器最小化您对 undefined 的使用,因为它现在只是一个局部变量。

标签: javascript inheritance knockout.js prototype


【解决方案1】:

由于您的BaseViewModel 只是将所有属性/方法添加到this(而不是使用原型),所以这很容易:

在您的新视图模型中,只需调用BaseViewModel

var MyVM = function () {
    var self = this;
    ko.BaseViewModel.call(self);

    self.somethingElse = ko.observable();
    self.itemCount = ko.computed(function() { return self.items().length; });
    self.items([1, 2, 3]); 
};


// ...
var vm = new MyVM();

【讨论】:

  • 嗯,这比我预期的要容易得多。现在我只需要弄清楚它是如何工作的!
  • ko.BaseViewModel.call(self) 行和 c# 中的 :base() 是一样的,对吧?
  • @theyshookhands 是的,它与:base() 调用相同。 ViewModel.prototype = new BaseViewModel() 与 c# 中的 Class : SubClass 相同。
  • @theyshookhands - 了解Function.call。它允许您调用任何函数并提供要使用的 this 值。在此示例中,BaseViewModel 只是用作帮助函数来初始化您的视图模型。我们并没有真的进行继承。当你开始使用原型时,事情会变得稍微有趣一些,原型是 JavaScript 的继承机制。
  • @Homer extend 技术分配一个新对象(BaseViewModel),然后将属性复制到您的子类对象并丢弃BaseViewModel 对象。所以浪费了分配。但更重要的是,如果BaseViewModel 定义了一些引用self 的函数或计算,它们将引用丢弃的对象而不是您的子类实例,因此extend 技术实际上会导致一些微妙且难以识别错误。
【解决方案2】:

Javascript 继承分两部分完成。第一个在构造函数中,第二个在原型上(你没有使用,所以你可以跳过)。

var ViewModel = function(data) {
    BaseViewModel.call(this);
};
//you only need to do this if you are adding prototype properties
ViewModel.prototype = new BaseViewModel();

最后一点,关于覆盖load,这与在您的视图模型上正常放置load 函数没有什么不同。 Javascript 允许你用任何东西覆盖任何对象的属性,这里没有特殊的步骤。

这里是fiddle demonstrating的继承。

【讨论】:

  • 如果您只需要担心支持现代浏览器,您可以将最后一行替换为Viewmodel.prototype = Object.create(BaseViewModel.prototype);,并避免以这种方式调用BaseViewModel 产生任何不良影响的一些棘手问题。
  • 在旧版浏览器中很容易填充Object.createvar objCreate = Object.create || function(o) { function F(){}; F.prototype = o; return new F(); };
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-04
  • 2013-04-19
  • 2011-11-27
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
  • 2010-11-25
相关资源
最近更新 更多