Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/466.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在复杂的web应用程序中构造Javascript程序?_Javascript_Architecture_Web Applications - Fatal编程技术网

如何在复杂的web应用程序中构造Javascript程序?

如何在复杂的web应用程序中构造Javascript程序?,javascript,architecture,web-applications,Javascript,Architecture,Web Applications,我有一个问题,很难描述。我正在编写一个web应用程序,它充分利用了jQuery和AJAX调用。现在我在Javascript架构方面没有太多经验,但我意识到我的程序没有很好的结构。我想我有太多的标识符指向同一件事(至少或多或少) 让我们看一看构成应用程序一小部分的任意示例性UI小部件:小部件可能是窗口的一部分,窗口可能是窗口管理器的一部分: EventHandler使用DOM元素作为参数。DOM元素表示浏览器中的小部件 很多时候,我使用jQuery对象(基本上是DOM元素的包装器)来处理小部件。有

我有一个问题,很难描述。我正在编写一个web应用程序,它充分利用了jQuery和AJAX调用。现在我在Javascript架构方面没有太多经验,但我意识到我的程序没有很好的结构。我想我有太多的标识符指向同一件事(至少或多或少)

让我们看一看构成应用程序一小部分的任意示例性UI小部件:小部件可能是窗口的一部分,窗口可能是窗口管理器的一部分:

  • EventHandler使用DOM元素作为参数。DOM元素表示浏览器中的小部件
  • 很多时候,我使用jQuery对象(基本上是DOM元素的包装器)来处理小部件。有时它们是暂时使用的,有时它们存储在变量中以供以后使用
  • AJAX函数调用为这些小部件使用字符串标识符。它们在服务器端进行处理
  • 除此之外,我还有一个widget类,其实例表示一个widget。它是通过新操作符实例化的
  • 现在,我有四个不同的对象标识符用于相同的东西,需要保持同步,直到重新加载页面。这似乎不是一件好事

    有什么建议吗?

    编辑:
    *@Will Morgan*:这是一个允许在浏览器中创建web表单的表单设计器。后端是Zope,一个python web应用服务器。很难更加明确,因为这是我在使用trio jQuery、DOM树和我自己的原型类实例进行Javascript开发时经常遇到的一个问题。 编辑2:
    我认为举个例子会有帮助,尽管是人为的。下面是一个logger小部件,可用于将块元素添加到显示日志项的网页中

    makeLogger = function(){
         var rootEl = document.createElement('div');
         rootEl.innerHTML = 'Logged items:';
         rootEl.setAttribute('class', 'logger');
    
         var append = function(msg){
               // append msg as a child of root element.
               var msgEl = document.createElement('div');
               msgEl.innerHTML = msg;
               rootEl.appendChild(msgEl);
         };
    
         return {
              getRootEl: function() {return rootEl;},
              log      : function(msg) {append(msg);}
         };
    };
    
    // Usage 
    var logger = makeLogger();
    var foo = document.getElementById('foo');
    foo.appendChild(logger.getRootEl());
    logger.log('What\'s up?');
    
    在这一点上,我有一个围绕HtmlLevel(托管对象)的包装器。有了logger实例(本机对象),我可以通过logger.getRootEl()函数轻松地使用它。
    当我手头只有DOM元素,需要使用函数makeLogger返回的公共API(例如,在事件处理程序中)执行某些操作时,我陷入了困境。这就是混乱开始的地方。我需要将所有本机对象保存在存储库或其他地方,以便再次检索。如果有一个从托管对象到本机对象的连接(例如对象属性),那就更好了。 我知道这是可以做到的,但它有一些缺点:

    • 这些类型的(循环)引用可能会导致IE7内存泄漏
    • 何时传递宿主对象以及何时传递本机对象(在函数中)
    现在,我使用jQuery的data()方法进行反向引用。但总而言之,我不喜欢跟踪托管对象与其本机对应对象之间关系的方式

    您如何处理这种情况?

    编辑3:
    我从Anurag的例子中获得了一些见解。
    *@Anurag:*如果我正确理解了您的示例,那么关键点是为事件处理程序设置正确的执行上下文(但正确的设置取决于您的需要)。在您的例子中,这是表示对象实例,它是通过Mootool的bind()函数完成的。所以你要确保你总是处理包装器对象(我称之为本机对象)而不是DOM对象,对吗?


    给读者的一个提示:您不必被迫使用Mootools来实现这一点。在jQuery中,您可以使用*$.proxy()*函数设置事件处理程序,或者如果您使用的是纯旧Javascript,则可以使用每个函数公开的*apply*属性。您可以使用全局注册表:

    window.WidgetRegistry = {};
    window.WidgetRegistry['foowidget'] = new Widget('#myID');
    
    当AJAX调用返回时,他们可以得到如下小部件:

    var widgetID = data.widgetID;
    if (widgetID in window.WidgetRegistry) {
        var widget = window.WidgetRegistry[widgetID];
    }
    
    对于您的jQuery调用:我猜它们相对便宜,因为jQuery缓存对象以供以后使用。但您可以使用以下方法扩展上述建议的
    WidgetRegistry

    通过这种方式,您可以存储附加到每个jQuery对象的小部件ID,并从全局注册表重新访问它

    测试,如果jQuery对象具有现有小部件:

    return $('#test').data('widget') &&
           ($('#test').data('widget') in window.WidgetRegistry);
    
    请注意,这些只是建议。实际上,有几十种方法可以实现这样的整合。如果您想将代码与jQuery更深入地结合起来,您可以这样做,这样您就可以编写如下内容:

    $('#widget').widget({'foo':'bar'});
    // and/or
    var allWidgets = $('*:widget');
    // ...
    

    我不确定我是否完全理解了你的问题,但我会尝试提出一些想法

    在我看来,您应该创建一个小部件基类,它包含小部件的通用功能

    让我们使用AppName.Widgets.base()作为示例。实例变量之一是_events,它是将事件存储为键并将函数存储为值的对象。这样,每个类都定义了这个小部件的事件,您可以轻松地在构造函数中绑定它们。至于字符串标识符,最简单的方法是使用toString()

    例如:

    namespace('AppName.Widgets'); // you can find implementations easy
    
    AppName.Widgets.base = function() {
        if (!this._type) return;
    
        this._dom = $('div.widget.'+this._type);
        for (var e in this._events) {
            this._dom.bind(e, this._events[e]);
        }
    
        this.toString = function() { return this._type; };
    }
    
    AppName.Widgets.example = function() { // extends AppName.Widgets.base
        this._type   = 'example';
        this._events = { 'click' : function(e) { alert('click'); }  };
    
        AppName.Widgets.base.call(this);
    }
    

    对于需要同步的四个对象,可以使用单个对象并在构造函数中传递引用,或者作为函数参数传递引用

    我解决这个问题的方法是永远不要丢失对包装器对象的引用。每当需要DOM对象时(例如插入页面),这个包装器对象就会提供它。但是将该小部件粘贴到屏幕上,包装器对象设置了所有特定于该小部件的事件处理和AJAX处理代码,因此在这些事件处理程序和AJAX回调中始终维护包装器的引用


    我使用MooTools在jsfiddle上创建了一个对您来说可能有意义的工具。

    您能做什么或不能做什么,很大程度上取决于您对javascript的控制程度。就我个人而言,我经常不得不使用其他人构建的库,所以我可能只能使用DOM节点,但我确实需要我的对象。在这些情况下,我发现
    namespace('AppName.Widgets'); // you can find implementations easy
    
    AppName.Widgets.base = function() {
        if (!this._type) return;
    
        this._dom = $('div.widget.'+this._type);
        for (var e in this._events) {
            this._dom.bind(e, this._events[e]);
        }
    
        this.toString = function() { return this._type; };
    }
    
    AppName.Widgets.example = function() { // extends AppName.Widgets.base
        this._type   = 'example';
        this._events = { 'click' : function(e) { alert('click'); }  };
    
        AppName.Widgets.base.call(this);
    }
    
    makeLogger = function(){
         var rootEl = document.createElement('div');
         rootEl.innerHTML = 'Logged items:';
         rootEl.setAttribute('class', 'logger');
    
         var append = function(msg){
               // append msg as a child of root element.
               var msgEl = document.createElement('div');
               msgEl.innerHTML = msg;
               rootEl.appendChild(msgEl);
         };
    
         var self = {
              getRootEl: function() {return rootEl;},
              log      : function(msg) {append(msg);}
         };
    
        // Save a copy to the domNode
        $(rootEl).data("logger", self);
        return self;
    };
    
    // Example of only getting the dom node
    function whatsUp (domNode){
       // Get the logger from the domNode
       $(domNode).data('logger').log('What\'s up?');
    }
    
    // Usage
    var logger = makeLogger();
    var loggerNode = logger.getRootEl();
    var foo = document.getElementById('foo');
    foo.appendChild(loggerNode);
    whatsUp(loggerNode);