I would like to know if I'm writing a plugin for jquery correctly. I followed the official guide and also added some tweaks that I've found from various sources over time.
While this works perfectly, I don't know if I'm doing something wrong.
This is the sample:
(function($)
{
var plugin = "my_plugin_name";
var methods = {
init : function(user_settings)
{
return this.each(function(index)
{
if(!$(this).hasClass("plugin_class"))
{
$(this).addClass("plugin_class");
var $this = $(this);
var data = $this.data(plugin);
if(!data)
{
var default_settings = {
optionA: "abc",
optionB: 123,
optionB: true
};
if(user_settings)
{
$.extend(true, default_settings, user_settings);
}
$this.data(plugin,
{
"settings": default_settings
});
}
privateMethod($this);
}
});
},
exposedMethodX : function(value) //$(selector).my_plugin_name("exposedMethodX", true)
{
console.log(value)
}
};
$.fn[plugin] = function(method)
{
if(methods[method])
{
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
}
else if(typeof method === "object" || !method)
{
return methods.init.apply(this, arguments);
}
else
{
alert("Method " + method + " does not exist");
}
};
function privateMethod(obj)
{
console.log(obj.data(plugin).settings);
}
})(jQuery);
2 Answers 2
From a short review;
- Please follow the lowerCamelCase naming convention,
user_settings
->userSettings
- In production code, never use
console.log
oralert
You set
optionB
twicevar default_settings = { optionA: "abc", optionB: 123, optionB: true };
The cyclomatic complexity would be lower if you exit immediately after the
hasClass
check:if($(this).hasClass("plugin_class")){ return; }
You could even consider using
filter
onhasClass
instead of checking foreach
"plugin_class"
should be a constant right undervar plugin
The following
if(user_settings) { $.extend(true, default_settings, user_settings); }
could be written as
$.extend(true, user_settings || default_settings);
In general the template looks like a good start. I noticed that the code appears to resemble the format advised in PHP-Fig's PSR-2, namely "The opening brace MUST go on its own line"1 for functions and methods plus control structures like if
and else
blocks. Most of the Javascript style guides I have seen call for curly braces to exist on the same line of the block they are opening. Personally I don't even agree with this in PHP, let alone Javascript, however if that is your personal preference then keep it consistent.
Inside the init
method, there is an iterator:
return this.each(function(index) { if(!$(this).hasClass("plugin_class")) { $(this).addClass("plugin_class"); var $this = $(this);
The reference var $this = $(this);
could be stored before the check of the class name and/or class name addition in order to reduce DOM queries.
Also, the name $this
could be more descriptive - at least something like $element
or $elem
(as shown in the example under Provide Public Access to Secondary Functions as Applicable from the Advanced Plugin Concepts).
Addressing Your Additional question
You asked in a comment:
what about the
$.fn[plugin]
part? I'm not sure about the first if statement. could that function be refactored and improved?
It is possible that ecmascript-6 features like the spread syntax could potentially be used to simplify the call, though given that current jQuery browser support includes IE 9+ it may not be wise to utilize ES-6 features.
-
\$\begingroup\$ thanks for your feedback. what about the
$.fn[plugin]
part? I'm not sure about the first if statement. could that function be refactored and improved? \$\endgroup\$Matías Cánepa– Matías Cánepa2019年07月08日 20:39:21 +00:00Commented Jul 8, 2019 at 20:39 -
\$\begingroup\$ I expanded my answer to address your question \$\endgroup\$2019年07月09日 21:08:03 +00:00Commented Jul 9, 2019 at 21:08
$(selector).my_plugin_name()
will work, also$(selector).my_plugin_name("exposedMethodX", 123)
\$\endgroup\$