【问题标题】:How to eliminate code repetition between different View Model modules?如何消除不同视图模型模块之间的代码重复?
【发布时间】:2013-12-18 22:06:40
【问题描述】:

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

我现在有两个视图模型 - 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;
}

这种方法有什么问题吗?

【问题讨论】:

    标签: javascript mvvm knockout.js


    【解决方案1】:

    如果你有两个子类型需要从同一个父类继承,你可以这样做:

    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"
    

    【讨论】:

    • 抱歉 - 它们都应该继承自一个其他函数。
    • 谢谢你。我尝试了您的建议,但在将所有内容放在一起时让自己感到困惑。我能够通过更新中的代码使其工作 - 您对这种方法有何看法?
    【解决方案2】:

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

    那么JavaScript 并没有给你在C# 中获得的继承和多态的全部功能。
    如果你想知道在 JS 中实现继承的方法:

    1. SO: Performing inheritance in JavaScript
    2. My Blog: Javascript Inheritance techniques

    回到你的问题,我认为你可能需要实现 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()
        })))));
    });
    

    【讨论】:

    • 你提到 JavaScript 是一种基于原型的语言,然后生成完全不使用它的示例代码,这有点有趣。
    • @HMR 你说得对.. 我只是想弄清楚如何解决这个问题,而不是详细解释继承
    • 谢谢 ebram。虽然我很困惑 - 这如何消除代码重复?我试图通过将共享代码从两个模块中推到一个共享模块中来变得更简单和更干。
    • 我认为 JS 没有提供你想要的灵活性。最后你必须说明你希望你的对象是哪个子类类型不是基类(在 JS 中没有多态性)
    【解决方案3】:

    查看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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-06
      • 2013-05-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多