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.
1 Answer 1
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.
-
\$\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\$jbarreiros– jbarreiros2014年03月26日 15:59:38 +00:00Commented 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 thethis
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\$David Harkness– David Harkness2014年03月26日 20:49:09 +00:00Commented 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\$jbarreiros– jbarreiros2014年03月27日 18:28:35 +00:00Commented 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\$Jeeva Jsb– Jeeva Jsb2019年09月13日 17:41:19 +00:00Commented Sep 13, 2019 at 17:41