如何消除不同View Model模块之间的代码重复?

时间:2013-12-03 01:31:10

标签: javascript mvvm knockout.js

我的JS被组织成视图模型和服务。这些服务主要关注AJAX调用,而我的viewModels描述了它们用于的视图。

我现在有两个视图模型 - StoreViewModel和MyStoreViewModel。在每一项中,我都有以下内容:

function MyStoreVm(model) {
    var self = this;

    self.doThis = function(){
        // do stuff 
        self.doThat();
    };
}

然后:

function StoreVm(model) {
    var self = this;

    self.doThis = function(){
        // do stuff 
        self.doThat();
    };
}

我来自C#背景 - 通常我会在这种情况下使用继承。如何通过让它们从第三个共享模块继承来消除两个不同模块/视图模型之间的代码重复?

更多细节:这些是在MVC视图中使用的,我根据商店是否为MyStore进行了敲除绑定:

@if (!Model.IsMyStore) {
    <script type="text/javascript">
        $(document).ready(ko.applyBindings(new StoreVm(@Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() })))));
    </script>
} else if (Model.IsMyStore) {
    <script type="text/javascript">
        $(document).ready(ko.applyBindings(new MyStoreVm(@Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }).Sanitize()))));
    </script>
}

更新

我查看了下面的一些建议,但似乎没有一个对我的新手技能来说足够干净和简单。我尝试了以下似乎有效:

function BaseStore(model){
    self.doThis = function(){
        // do stuff 
        self.doThat();
    };
    // and a whole lot of other shared code
}

function StoreVm(model) {
    var storeVm = new BaseStoreVm(model)
    var self = storeVm;
    self.isolatedFunctionForGenericStores = function(){stuff}
    // other stuff for only this type
    return storeVm;
}

function MyStoreVm(model) {
    var myStoreVm = new BaseStoreVm(model)
    var self = myStoreVm;
    self.isolatedFunctionForMyStore = function(){stuff}
    // other stuff for only this type
    return myStoreVm;
}

这种方法有什么问题吗?

3 个答案:

答案 0 :(得分:2)

如果您有两个需要从同一父级继承的子类型,则可以执行以下操作:

function Parent( foo ) {
  this.foo = foo;
}
Parent.prototype.method = function() {
  console.log( this.foo );
};

function Child1() {
  Parent.call( this, "bar" );
}
Child1.prototype = Object.create( Parent.prototype );
Child1.prototype.constructor = Child1;

function Child2() {
  Parent.call( this, "qux" );
}
Child2.prototype = Object.create( Parent.prototype );
Child2.prototype.constructor = Child2;

var parent = new Parent("blah");
var child1 = new Child1();
var child2 = new Child2();

parent.method();  // => "blah"
child1.method();  // => "bar"
child2.method();  // => "qux"

答案 1 :(得分:0)

首先,您应该了解JavaScript如何实现继承。 JavaScript是一种基于原型的语言,不包含类语句,例如C#中的语句。相反,它使用函数作为类(没有类,只有对象) 所以我们这里有 对象 继承自其他 对象 现在你可能需要得到一些咖啡)。

因此,JavaScript并没有为您提供C#中的继承和多态性的全部功能。
如果你想知道在JS中实现继承的方法:

  1. SO: Performing inheritance in JavaScript
  2. My Blog: Javascript Inheritance techniques
  3. 回到您的问题,我认为您可能需要实施 The Factory Pattern 。所以你的js代码可能是这样的:

    function MyStoreVm(model) {
        var self = this;
        self.doThis = function() {
            // do stuff 
            self.doThat();
        };
    }
    
    function StoreVm(model) {
        var self = this;
        self.doThis = function() {
            // do stuff 
            self.doThat();
        };
    }
    // Define factory object that create your proper store object
    // StoreFactory takes the model as input.
    // You can change it to accept seconf parameter that define class type
    function StoreFactory() {
        this.classType == "MyStoreVm"; // default value
        this.createStore = function(model) {
            if (model.IsMyStore === true)
                this.classType = MyStoreVm;
            else
                this.classType = StoreVm;
            return new this.classType(model);
        }
    }
    

    然后在你的MVC视图中:

    $(document).ready(function() {
        var mystoreFactory = new StoreFactory();
        ko.applyBindings(mystoreFactory.createStore((@Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        })))));
    });
    

答案 2 :(得分:0)

结帐Klass.js。虽然这与创建自己的原型和继承方法基本相同,但它很好用。这也是AMD意识到的。

// base class
var Store = klass(function() {
    var self = this;
    // add properties here
}).methods({
    doThis: function () {
        // do this
    },
    doThat: function () {
        // do that
    }
});
return Store;

// create the first constructor
var myStoreVm = Store.extend(function () {
    // super class is called
}).methods({
    doThis: function(){
        this.supr(); // call Store.doThis
        // some other code
    }
});
return myStoreVm;

// create the second constructor
var storeVm = Store.extend(function () {
    // super class is called
}).methods({
    doThis: function(){
        // override Store.doThis with my own code
    }
});
return storeVm;