javascript - 对如何使用模块模式的困惑

标签 javascript events design-patterns

我对如何在 JavaScript 中使用模块模式(以及一般的设计模式)感到困惑。

我已经使用模块模式在我的应用程序中编写了一些功能代码,这些代码可以完成我想做的事情,但它对我来说似乎不是很模块化,而且我一直有这种感觉,我做错了。我没有找到任何具有任何设计模式的具体且完整的应用程序示例。

这是我如何使用它:

假设我的应用程序中有一些表单,将用于不同的模块(发布线程、回复线程、评论宾客簿),通过一些 JavaScript,我将为用户提供一些功能,例如弹出一个笑脸气泡并处理它们在我的表单中的插入,将数据发送到我的服务器代码以返回 HTML 代码,以便在不重新加载页面的情况下添加消息,我将执行类似的操作:

    let Form = function (selector_form, selector_textarea, selector_emoticonsButton, selector_postButton) {

      let form, textarea, emoticonsButton, postButton;
      let emoticonsBubble = new EmoticonsBubble()

      return {
        selectors: function () {
          return {
            form: function () { return selector_form },
            sendButton: function () { return selector_sendButton }
          }
        }

        setElements: function (obj) {
          form = $(obj).get(0);
          textarea = $(form).find(selector_textarea).get(0);
          emoticonsButton = $(form).find(emoticonsButton).get(0);
          postButton = $(form).find(selector_postButton).get(0);

          emoticonsBubble.setElements(form, emoticonsButton);
        },

        get: function () {
          return {
            form: function () { return form },
            //...
            emoticonsBubble: function () { return emoticonsBubble }
          }
        },

        post: function (moduleId, callback) {
          $.ajax({
          //parameters
          }).done(function (data) {
            callback(data);
          });
        }
      }
    }

    let EmoticonsBubble = function () {

      let thisContainerToAppendTo, thisTextarea;

      return {
        setElements: function (container, textarea) {
          thisContainerToAppendTo = container;
          thisTextarea = textarea;
        },

        pop: function () {
          this.ajax().pop(function (data) {
            $(thisContainerToAppendTo).append(data);
          });
        }

        insert: function (emoticon) {
          $(thisTextarea).append(emoticon);
        },

        ajax: function () {
          return {
            pop: function (callback) {
              $.ajax({
              //parameters
              }).done(function (data) {
                callback(data);
              });
            }
          }
        }
      }
    }

    // Events part

    let form = new Form('#threadForm', '.textarea', 'button[name="emoticons"]', 'button[name="send"]');
    let emoticonsBubble = form.get().emoticonsBubble();

    $(form.selectors().form()).on('click', function (e) {
      form.setElements(this);
    });

    $(form.selectors().sendButton()).on('click', function (e) {
      let moduleId = // retrieve module id, if it belongs to guests book, thread creation module or reply module
      form.post(moduleId, function (data) {
        // append data to something
      });
    });

    // etc for emoticons handling

事实上,我必须为应用程序中的每种不同形式重写事件部分,同时保持除变量名称之外的所有内容相同,这让我很烦恼。

你们能告诉我如何处理这些功能以及我的编码方式可能有什么问题吗?

最佳答案

模块模式旨在防止代码单元与其他作用域(通常是全局作用域)发生冲突。

众所周知,在 JavaScript 中,变量定义为:

  • letconst 的作用域为其父 block
  • var 的作用域为它们包含的函数(如果不在一个函数中则为全局) 函数)

所以,如果您要使用 Form 函数:

let Form = function (x,y,z) {

  let form, textarea, emoticonsButton, postButton;
  let emoticonsBubble = new EmoticonsBubble()

  return {
        . . . 
    }

    setElements: function (obj) {
        . . . 
    },

    get: function () {
        . . . 
    },

    post: function (moduleId, callback) {
        . . . 
    }
  }
}

变量Form是全局的,因为没有包含 block 。这是一个问题,因为如果已经有另一个名为 Form 的 Global(很可能是因为“Form”一词的通用性质)怎么办?所以,这段代码并不会阻止你的代码被暴露。要在其上使用模块模式,我们将用 IIFE(立即调用函数表达式)包装它,并在该 IIFE 中,我们将在全局范围内创建一个我们确信不存在的自定义命名空间(从而避免名称冲突):

(function(){
  // This is going to be exposed as publicly available via the module namespace
  function Form(x,y,z) {
    . . .
  }

  // This will remain private within the module
  function helper(){

  }

  // **********************************************************************    
  let temp = {};    // Create a temporary object to bind only the public API
  temp.Form = Form; // Bind the public members to the object

  // Expose the module to the Global scope by creating a custom namespace 
  // and mapping the temp object to it
  window.myCustomAPI = temp;
})();

// Now, outside of the module (in some higher scope), your public portions
// of the Module are accessible:
let myForm = new myCustomAPI.Form(arg, arg, arg);

关于javascript - 对如何使用模块模式的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55762060/

相关文章:

javascript - Safari 上的字体问题

javascript - NodeJs,500 无法获取访问 token (错误 : connect ECONNREFUSED) at at process. _tickCallback (node.js:419:13)

java - 框架监听器Java

java - 按顺序执行两个 Action

java - Java API 中的构建器模式示例?

php - PHP 中的 ORM 和事件记录模式?

javascript - AJAX 查询并不总是一致地更新信息

javascript - 如何使用 Puppeteer 在 div 内滚动?

android - 将事件添加到 Android 日历

design-patterns - JPA 查找表设计