8
\$\begingroup\$

For non-plugin code, I generally use the module pattern, but I'm working on a jQuery plugin and decided to try out the "lightweight start" pattern. The problem is, I find myself needing $.proxy when calling private methods to ensure the this context.

Is there a better way to structure the code in order to avoid $.proxy, while ensuring the private methods have access to the init() method's this context? Where exactly should I define private properties?

Jsfiddle example without $.proxy ... also have a jsfiddle example using $.proxy

(function(,ドル window, document, undefined) {
var pluginName = "myPlugin",
 defaults = {
 opt1: "#opt1",
 };
function Plugin(element, options) {
 this.element = $(element);
 this.options = $.extend( {}, defaults, options);
 this._defaults = defaults;
 this._name = pluginName;
 this.init();
}
Plugin.prototype.init = function() {
 this.counter = 1;
 $("div").each(privateMethod1);
 $("body").on("click", this.options.opt1, event1);
};
function privateMethod2(i, div) {
 // "this" context is Window, not Plugin
 $(div).append(i);
 this.element.append(this.counter); 
};
function privateMethod1(i, el) {
 // "this" context is Window, not Plugin
 this.counter += 1; // undefined, but defined in init()
 privateMethod2(i, el);
};
function event1(ev, el) {
 this.counter += 1; // undefined, but defined in init()
 privateMethod1(this.counter, el);
};
$.fn[pluginName] = function(options) {
 return this.each(function() {
 if (!$.data(this, "plugin_" + pluginName)) {
 $.data(this, "plugin_" + pluginName, new Plugin(this, options));
 }
 });
};
}(jQuery));


Edit:

What I learned. This pattern appears to actually make all methods private. This is because the if (!$.data(this, "plugin_" + pluginName)) { has no else block to handle elements that already have a reference to the plugin. To allow a method to be called, check out https://stackoverflow.com/a/14128485/536734.

asked Mar 26, 2014 at 5:25
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

You could use a closure to create your own proxy.

Plugin.prototype.init = function() {
 var self = this;
 rows.each(function (groupIndex, group) {
 self.initGroup(groupIndex, group);
 });
 this.container.on("click", this.options.addBtnId, function (ev) {
 self.addGroup(ev);
 });
};

(削除) Why are initGroup and addGroup using $.proxy? They are already being called with the correct this context, and rebinding to the same context changes nothing. (削除ここまで)

Edit: Instead of using plain functions to implement "private methods", promote them to proper object methods and mark them private using JSDoc. This will save you those extra calls to $.proxy.

/** @private */
Plugin.prototype.initGroup = function(groupIndex, group) {
 this.addFieldIds(groupIndex, group);
};
/** @private */
Plugin.prototype.addGroup = function(ev) {
 this.initGroup(this.maxGroupIndex, newGroup);
};

In my opinion, forcing developers to jump through hoops just to hide private methods is a net loss.

answered Mar 26, 2014 at 6:51
\$\endgroup\$
4
  • \$\begingroup\$ I found that without $.proxy, I lost access to any variables (this.counter) created within init(). -- Should private properties be defined outside of the init() method? \$\endgroup\$ Commented Mar 26, 2014 at 15:59
  • 1
    \$\begingroup\$ @jbarreiros Ah, I didn't realize the private methods were plain functions and not object methods. If you want to use this inside them, you have to use something to bind the this context in the method call. $.proxy works for this, but you can instead make them proper object methods and mark them private in the documentation. See the updated fiddle. \$\endgroup\$ Commented Mar 26, 2014 at 20:49
  • \$\begingroup\$ Got it. I was under the impression that adding the function to the prototype would make it "public", but looking closer at the syntax, I realize now that you can't actually call any of the methods from outside due to the if (!$.data(this, "plugin_" + pluginName)) { conditional. \$\endgroup\$ Commented Mar 27, 2014 at 18:28
  • \$\begingroup\$ What is the difference between private function vs prototype function? why should not go with private functions? \$\endgroup\$ Commented Sep 13, 2019 at 17:41

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.