如何在一个真实的例子中使用javascript模块模式?

时间:2012-08-20 17:31:46

标签: javascript jquery design-patterns module-pattern

我正在尝试理解JavaScript模块模式。我已经看到它应该是什么样子的例子,但我不明白如何使用它。

例如,这里发生了一些事情:

$('input#share').on("click", function() {

    $('.loading').html('<img class="remove_loading" src="/graphics/loading.gif" />');

    var message = $(".wallmessage").val();

    if (message == ""){
        $("#messageempty").jmNotify();
        $('.remove_loading').remove();
    } else {
        addMessage(message);
    }

    return false;
});


function addMessage(message)
{
    $.ajax({
        url: '/test',
        type: 'POST',
        dataType: "json",
        data: {'message' : message},
        success: function(data) {
                ...
        },
        error: function() {
            ...
        }
    });
}

如何将上述示例用于:

var myTest = function() {
    var selectId;
    function addMessage () {
        // ...
    }
    return { // public interface
        publicMethod1: function () {
            // all private members are accesible here
        }
    };
};
var start = myTest();

我在哪里添加click事件,声明我的vars,使用ajax调用添加addMessage函数。并调用addMessage函数?我是否必须将所有内容都包裹在$(document).ready(function()

有人能为我解释一下吗?

由于

5 个答案:

答案 0 :(得分:20)

这是一个很自以为是的主题,但我会这样做(不完全知道你的完整应用及其功能),有点像这样:

var myApp = (function() {

  var someElement = $("#foo"); //some element I know I'll use lots

  var addMessage = function(message) {
    $.ajax({
      url: '/test',
      type: 'POST',
      dataType: "json",
      data: {'message' : message},
      success: function(data) {
              ...
      },
      error: function() {
          ...
      }
    });
  };

  var inputClick = function(event) {
    event.preventDefault();
    //depending on if you'll reuse these selectors throughout the app I might have these as variables
    $('.loading').html('<img class="remove_loading" src="/graphics/loading.gif" />');

    var message = $(".wallmessage").val();

    if (message == ""){
      $("#messageempty").jmNotify();
      $('.remove_loading').remove();
    } else {
      addMessage(message);
    }
  };

  var bindFunctions = function() {
    $("input#share").on("click", inputClick)
  };

  var init = function() {
    bindFunctions();
  };

  return {
    // EDIT: 27/12/16 - need to return init for 'usage' example to work
    init: init,
    addMessage: addMessage
    //anything else you want available
    //through myApp.function()
    //or expose variables here too
  };


})();

//usage

myApp.init();

你的模式的原始代码是错误的,函数必须在最后有(),使它成为一个立即被调用的函数,然后执行,暴露任何东西通过return statement

你可能希望与我所做的略有不同,这只是一个基本的想法,但我希望它可以让你开始。

有人回过头来问了一个与此模式有关的问题,I answered it解释了为什么我们使用(function() {})();以及return语句如何在这种情况下起作用,如果你有点困惑的话它也许值得一读。

答案 1 :(得分:12)

显示模块模式的用法如下:

var moduleName = (function () {
    var privateVariable = 'private';

    var privateMethod = function () {
        alert('this is private');
    };

    // this is the "revealed" part of the module
    return { 
        publicVariable: 'public',
        publicMethod: function () {
            alert('this is public');
        }
    };
}());

您还可以将公共变量/方法定义为私有,然后公开对它们的引用,使它们公开。这是一个偏好的问题。

在您的示例中,如果您希望addMessage成为模块的一部分,您可以这样做:

var moduleName = (function () {
    // this becomes public due to the reference exposure in the return below
    var addMessage = function () {
        // do whatever
    };

    // this is the "revealed" part of the module
    return { 
        addMessage: addMessage
    };
}());

moduleName.addMessage();

答案 2 :(得分:1)

我们的想法是通过将代码划分为多个部分/模块来降低外部世界的可见性和更好的代码管理。如果您希望看到模块化设计模式的真正良好使用以及我们如何能够实现的方式,请查看从中受益。
http://learn.jquery.com/code-organization/concepts/

答案 3 :(得分:1)

与JAVA不同,Javascript没有私有和公共属性或方法的概念。让我们创建一个名为person的对象,它有2个属性firstName和lastName,还创建了2个函数,它们将成为我们属性的getter。在Javascript中,我们可以创建函数作为对象的属性&amp;这些功能可以像任何其他地方一样随处访问。

var person={
  "firstName":"Anoop",
  "lastName":"Rai",
  "getFirstName":function(){
    return this.firstName;
  },
  "getLastName":function(){
    return this.lastName;
  }
};
console.log(person.getFirstName());
console.log(person.firstName);

如上所述,代码11打印Anoop和Anoop。嗯,这对于面向对象的编程来说并不好。好吧,我们成功实现了getter,所以我们也应该有公共范围的setter,属性应该标记为私有范围(这些私有和公共概念属于JAVA,C ++类似于语言)。我们的意图是好的,让我们应用特定于Javascript的概念。我们不想做person.firstName,我们希望直接阻止属性的访问。在像JAVA这样的语言中,由于私有和公共,我们实现了属性的受控控制,但在Javascript中,一切都是公开的。

Javascript使用闭包的概念来实现私有和放大的东西。上市。此模式称为模块模式。也就是说,隐藏变量来自公共访问。为了实现范围,请将代码包装在函数中(请记住,范围是通过Javascript中的函数实现的)。

function createPerson(){
  var returnObj={
    "firstName":"Anoop",
    "lastName":"Rai",
    "getFirstName":function(){
      return this.firstName;
    },
    "getLastName":function(){
      return this.lastName;
    }
  };
  return returnObj;
}
var person=createPerson();
console.log(person.getFirstName());
console.log(person.firstName);

现在上面的行也印有Anoop和Anoop。仍然没有成功。只要属性与对象绑定,就可以直接访问它。让我们解开它。我们不是使用属性来创建函数作用域的变量(闭包变量)。

function createPerson(){
  var firstName="Anoop";
  var lastName="Rai";
  var returnObj={
    "getFirstName":function(){
      return firstName;
    },
    "getLastName":function(){
      return lastName;
    }
  };
  return returnObj;
}
var person=createPerson();
console.log(person.getFirstName());
console.log(person.firstName);

现在上面的行打印Anoop和undefined。这是怎么发生的?由于闭包,当函数getFirstName和getLastName被创建时,函数具有整个范围链或指向相关变量的指针,即firstName和lastName。对象returnObj不记得变量,但由于闭包,函数对象会记住这些变量。看起来我们已经实现了我们想要的东西,但是剩下一件事就是设置了firstName和lastName的受控访问。让我们实现setter。

function createPerson(){
  var firstName="Anoop";
  var lastName="Rai";
  var returnObj={
    "getFirstName":function(){
      return firstName;
    },
    "getLastName":function(){
      return lastName;
    },
    "setFirstName":function(name){
      return firstName=name;
    },
    "setLastName":function(name){
      return lastName=name;
    }
  };
  return returnObj;
}
var person=createPerson();
console.log(person.getFirstName());
person.setFirstName("Kumar");
console.log(person.getFirstName());

我们成功修改了firstName但是以受控方式。

http://jkoder.com/the-module-pattern-javascript-way-of-hiding-data-in-objects-from-public-access/

答案 4 :(得分:0)

我有一些Mootools的经验,但我是一个jQuery新手。我已经阅读了文档,看起来组织代码最聪明的方法是模块模式,所以我正在尝试这样做。然而,这种风格似乎缺少的一点是任何“自我”概念,因为IIFE中的每个变量都是一个独立的对象(没有双关语)。

所以...也许这会破坏整个目的,但是你能做到这样的事情,并且在模块模式风格有效的所有方面仍然是“有效的”吗?

var feature = ( function () {

    var self = {

        config: {
            option1: 'thing 1',
            option2: 'thing 2'
        },


        init: function (options) {

            // allow overriding the default config
            jQuery.extend( self.config, options );

            self.doSomething();

        },

        doSomething: function () {

        },

    };

    return {
        init: self.init
    }

})();

我喜欢这个是我可以使用“self”在内部引用所有方法和属性。我仍然能够使用“return”对象公开我想要的方法,所以(我猜)没关系。但我是一个新手,这看起来很简单,(乍看之下)优雅,我必须错过一个主要问题。它与Object Literal格式共享编码风格,这是我从Mootools熟悉的。所以也许我正试图将一个圆形钉固定在一个方孔中。也许内部对象文字不是必需的,因为我可以说“doSomething”而不是“self.doSomething()”。是这样的吗?

部分我喜欢这个,因为我可以将$ .ajax的“context”参数设置为“self”,这似乎是一种胜利。