开发者

Can the Javascript Module Pattern be used for singletons and also for objects that are instantiated mutliple times?

开发者 https://www.devze.com 2023-01-08 20:29 出处:网络
I have one page with two types of forms.I have a single form of type A at the top, and then I have 1 or more forms of type B below it.

I have one page with two types of forms. I have a single form of type A at the top, and then I have 1 or more forms of type B below it.

I use the Module pattern + jQuery to wire up all the events on my forms, handle validation, ajax calls, etc.

Is this the preferred/valid way to define a singleton, as in Form A, and a reusable object class, as in Form B? They are very similar and I'm not sure if I need to be using object the prototype property, new, or a different pattern. Everything seems to work for me but I'm afraid I'm missing some key error.

Form A javascript looks like this:

var MyProject.FormA = (function() {
  var $_userEntry;
  var $_domElementId;

  var validate = function() { 
    if($_userEntry == 0) {
      alert('Cannot enter 0!');
    } 
  }
  var processUserInput = function() {
    $_userEntry = jQuery('inputfield', $_domElementId).val();
    validate();
  }
  return {
    initialize: function(domElementId) {
      $_domElementId = domElementId;
      jQuery($_domElementId).click(function() {
        processUserInput();
      }
    }
  }

})();
jQuery(document).ready(function() {
  MyProject.FormA.initialize('#form-a');
});

Form B, which is initialized one or many times, is defined like so:

var MyProject.FormB = function() {
  var $_userEntry;
  var $_domElement;

  var validate = function() { 
    if($_userEntry == 0) {
      alert('Cannot enter 0!');
    } 
  }
  var processUserInput = function() {
    $_userEntry = jQuery('inputfield', $_domElement).val();
    validate();
  }
 开发者_运维问答 return {
    initialize: function(domElement) {
      $_domElement = domElement;
      jQuery($_domElement).click(function() {
        processUserInput();
      }
    }
  }

};
jQuery(document).ready(function() {
  jQuery(".form-b").each(function() {
    MyProject.FormB().initialize(this);
  });
});


Both of your modules explicitly return objects which precludes the use of new.

Prototype inheritance isn't really compatible with the method hiding your achieving with this pattern. Sure you could re-write this with a prototype form object with your validate method defined on it, but then this method would be visible and you'd loose the encapsulation.

It's up to you whether you want the low memory footprint and speedy object initialization of prototypes (Shared methods exist only once, Instantiation runs in constant time) or the encapsulation of the module pattern which comes with a slight performance penalty (Multiple defined identical methods, Object instantiation slowed as every method has to be created every time)

In this case I would suggest that the performance difference is insignificant, so pick whatever you like. Personally I would say there is too much duplication between them and I would be inclined to unify them. Do you really need A to be a singleton? What are the dangers of it being accidentally instantiated twice? Seems like this is maybe over-engineering for this problem. If you really must have a singleton I'd wrap the non-singleton (B) class like this:

var getSingleton = function() {
    var form = MyProject.FormB();
    form.initialize("#form-a");
    console.log("This is the original function");
    getSingleton = function() {     
        console.log("this is the replacement function");
        return form;
    }
    return form;
}


I think you just need to write a kind of jQ plugin:

(function($) {
    $.fn.formValidator = function() {
        return $(this).each(function() {
            var $_domElement = $(this);
            $_domElement.click(function() {
                if($('inputfield', $_domElement).val() == 0) {
                    alert('Cannot enter 0!');
                }
            });
        });
    };
})(jQuery);

In this case you'll extend jQ element methods module and will be able to use it for any amount of elements at the page (for single or multiple elements collection). Also it will be chainable.

Usage:

$('#form-a').formValidator();
$('.form-b').formValidator();

Or

$('#form-a, .form-b').formValidator();

Ofcourse you can use a module to store this function:

ProjectModule.formValidator = function(selector) {
    return $(selector).each(function() {
        var $_domElement = $(this);
        $_domElement.click(function() {
            if ($('inputfield', $_domElement).val() == 0) {
                alert('Cannot enter 0!');
            }
        });
    });
};

Usage:

ProjectModule.formValidator('#form-a, .form-b');
0

精彩评论

暂无评论...
验证码 换一张
取 消