【问题标题】:JavaScript OOP and MVCJavaScript OOP 和 MVC
【发布时间】:2013-07-26 12:42:19
【问题描述】:

我正在尝试找出许多现有的 MV* 框架可以满足我的需求...

  1. 我正在使用多页 ASP.NET Web 应用程序,所以我不想使用路由器。

  2. 它必须非常小……像 Backbone.js,目前我不想使用像 Ember.js 或 Angular.js 这样大的东西。

  3. 我将拥有实际上是“单个实例”的“模块或控制器”,它们将从服务器作为 JSON 对象获取它们的“数据”(有时是 AJAX,有时是嵌入在 HTML 中)。能够为模块使用继承很重要,所以希望能够做这样的事情(伪代码):

    App.Module1 = SomeFramework.create({ 
        model: null, 
        init:function(data){ this.model = data } 
    });
    App.Module2 = SomeFramework.create(App.Module1, { 
        config: null, 
        init: function(data, config){ 
              this._super(data); this.prop = data; 
        } 
    });
    
    //Later I will use one of this modules
    App.Module1.init(data); /* OR */ App.Module2.init(data, config);
    
  4. 我会有不同的模型,可以有很多实例。

  5. 模块/控制器应该能够检测“模型更改”。

我喜欢 Backbone,但它遗漏了一些东西,比如创建能够被继承的“单个模块”,而 Backbone 没有“控制器”,因为它现在是路由器,它基于 URL 创建实例。

【问题讨论】:

    标签: javascript oop model-view-controller


    【解决方案1】:

    没有什么比编写普通的 javascript 更简单的了,这将是我的建议。

    如果需要,还可以添加几个 micro libraries 用于 DOM 操作和 ajax。

    你想观察你的模型,但数据绑定可能很繁重,魔法是有代价的。为什么不直接使用 pub-sub 库与模型数据已更改的模块进行通信?它简单、小巧、安全。

    我将用我知道的框架soma.js 为您提供一些示例。它非常轻量级,没有路由器(我通常建议使用director.js)。它提供依赖注入、基于事件的观察者系统,以及基本的 OOP,如继承。它非常专注于避免高度耦合的代码,因此模块是可维护和可重用的。 Vanilla javascript 是可能依赖注入的关键。

    有趣的是,有人认为我来自具有该框架的 .NET 背景,也许它对你很有吸引力。

    对于 ajax 部分,去掉 jquery 以便只有 ajax 的东西(所以它很小),或者使用类似 reqwest 的东西。

    这里是您可以做什么的快速概览。

    Inheritance

    // create "super class"
    var Person = function(name) {
      this.name = name;
    };
    Person.prototype.say = function() {
      console.log("I'm a Person, my name is:", this.name);
    }
    
    // create "child class" that will inherit from its parent
    var Man = function(name) {
      Person.call(this, name); // call super constructor
    }
    Man.prototype.say = function() {
      // Person.prototype.say.call(this); // call super say method
      console.log("I'm a Man, my name is:", this.name);
    }
    
    // apply inheritance
    soma.inherit(Person, Man.prototype);
    
    // create Person
    var person = new Person("Doe");
    person.say();
    
    // create Man
    var john = new Man("John Doe");
    john.say();
    

    Try it out

    这是另一个带有一些快捷方式的示例。

    // create "super class"
    var Person = function(name) {
      this.name = name;
    };
    Person.prototype.say = function() {
      console.log("I'm a Person, my name is:", this.name);
    }
    
    // create an "extend" shortcut
    Person.extend = function (obj) {
      return soma.inherit(Person, obj);
    };
    
    // create "child class" and apply inheritance using an "extend" shortcut
    var Man = Person.extend({
      constructor: function(name) {
        Person.call(this, name); // call super constructor
      },
      say: function() {
        // Person.prototype.say.call(this); // call super say method
      console.log("I'm a Man, my name is:", this.name);
      }
    });
    
    // create Person 
    var person = new Person("Doe");
    person.say();
    
    // create Man
    var john = new Man("John Doe");
    john.say();
    

    Try it out

    模块

    这些框架使您能够使用原生 javascript,因此它非常可重用。

    这是模型、模块或其他任何东西的样子(原版 javascript):

    (function(clock) {
    
        'use strict';
    
        var TimerModel = function() {
    
        };
    
        TimerModel.prototype.update = function() {
            // update something
        };
    
        TimerModel.prototype.add = function(callback) {
            // add something
        };
    
        TimerModel.prototype.remove = function(callback) {
            // remove something
        };
    
        TimerModel.prototype.dispose = function() {
            // destroy model
        };
    
        clock.TimerModel = TimerModel;
    
    })(window.clock = window.clock || {});
    

    Dependency injection

    框架提供依赖注入,这使您能够使用命名变量在其他模块中获取您的实例。

    注入规则可能如下所示:

    injector.mapClass("myModel", Model);
    

    要将您的模型放在其他地方,只需使用“命名变量”,注入器将处理所有事情(也非常适合解决嵌套依赖项):

    var Module = function(myModel) {
        // myModel has been injected
    }
    

    Try an example

    More information

    Communication (pub-sub, Observer Pattern)

    一个基于事件的工具(可与 DOM 节点互换以实现高度解耦)可用于通信:调度程序。您也可以通过注射获得它:

    var Module = function(myModel, dispatcher) {
        // myModel and dispatcher have been injected
    }
    

    调度事件:

    this.dispatcher.dispatch('do-something');
    

    收听一个事件:

    dispatcher.addEventListener('do-something', function(event) {
      // react to an event
    });
    

    Template

    您可以使用一个非常强大的插件作为模板引擎(真正的非破坏性 DOM 操作),称为 soma-template

    或您选择的任何其他模板引擎。

    构建应用程序

    这是一篇帮助您构建可扩展且可维护的应用程序的文章: http://flippinawesome.org/2013/07/15/soma-js-your-way-out-of-chaotic-javascript/

    不是这样,框架还提供MediatorsCommands 让你的代码可重用。 Check out the site,有tons of demos

    我希望这一切对你有所帮助。

    我习惯于编写可以在移动设备上快速运行的非常简单的应用程序,所以请向我询问有关您需要什么的确切问题,以便我可以提供帮助。

    罗姆

    【讨论】:

    • 非常感谢您的详细回答!当然,我需要更仔细地研究 somajs,它看起来真的很像我需要的。我已经喜欢它的 DI 功能,但是 somajs 如何解决“缩小”问题?如果我会有类似的东西 injector.mapClass("config", Config); var 模型 = 函数(配置){};然后将缩小 JS 文件,因此变量名称将更改为更短......那么 somajs 将如何仍然能够注入依赖项?无论如何,我在 somajs 网站上花了 5 分钟来看看它能做什么,我真的很喜欢它!这个框架有多老?它有大型社区吗?
    • 缩小确实是你必须关心的 DI。你需要看看一个叫做 Mangle 的东西。如果您使用的是 uglify,这里是答案的开头:groups.google.com/forum/#!topic/somajs/twPrU9_wLhQ 我通常会关闭 mangle,以免在开发过程中妨碍它,稍后我会添加要优化的异常列表。有人指出,你可以摆脱这样的事情:this['model'] = null;但我不太喜欢它,我更喜欢用 mangle 管理注入名称。
    • 这个框架很新,所以现在社区很小,但似乎很吸引人。尤其是关心依赖和/或以其他语言为背景的开发人员。我尽量让自己有空,如果您有任何需要,我很乐意为您提供帮助:groups.google.com/forum/#!topic/somajs
    【解决方案2】:

    是的,Backbone 没有模块驱动的开发,或者说 Backbone 不遵循模块化模式。您可以将 require.js 用于模块化模式。这是一个非常小的库,并且可以很好地与 Backbone 同步。

    【讨论】:

      猜你喜欢
      • 2011-09-16
      • 2016-04-21
      • 1970-01-01
      • 2016-11-28
      • 1970-01-01
      • 1970-01-01
      • 2013-05-03
      • 1970-01-01
      • 2011-08-23
      相关资源
      最近更新 更多