Background
So, I came across an article Essential jQuery Plugin Patterns a few months ago. I was trying to write a simple jQuery plugin and I found this article very useful. It contains a lot of information, most of which is beyond my expertise of JavaScript or jQuery. The main thing of interest was the first plugin template, dubbed jQuery Lightweight Plugin Boilerplate, which I referenced in another question a few months ago.
Recently, I started using CoffeeScript and looked up for a CoffeeScript jQuery Plugin Template, which I found here.
Both of these implement a pretty much same concept. Some of the important things different here are:
- The private objects that are not there in the Lightweight Boilerplate
- The namespacing block that is different in the CoffeeScript Template. (I have absolutely no idea what he did with
methods[method].apply this, Array::slice.call(arguments, 1)
though I somewhat understand the namespacing block of Lightweight Boilerplate. - In Lightweight Boilerplate chainability and iteration over objects is taken care of in the namespacing block, whereas in CoffeeScript Template
method.init()
needs toreturn $(this)
as well as do$(this).each()
.
Research
So I went ahead and spliced both of these. I wrote my own template. Here it goes:
(($, window, document) ->
# ---------------------------------------------------------------------------
# Conventionally private variables
# ---------------------------------------------------------------------------
_PluginName = "FooBar"
_Defaults =
property: 'value' # etc. etc.
# ---------------------------------------------------------------------------
# Private methods
# ---------------------------------------------------------------------------
_Debug = (msg) ->
window.console.log(msg)
return
# ---------------------------------------------------------------------------
# Plugin Constructor
# ---------------------------------------------------------------------------
Plugin = (element, options) ->
@element = element
@options = $.extend true, {}, _Defaults, options
# TODO: Call methods to do stuff
return
# ---------------------------------------------------------------------------
# Plugin Methods
# ---------------------------------------------------------------------------
Plugin.prototype.init = () ->
# TODO: Plugin initializiation logic
return
Plugin.prototype.destroy = () ->
# TODO: Cleanup, unbind and eject
return
# ---------------------------------------------------------------------------
# Actual plugin body
# ---------------------------------------------------------------------------
$.fn[_PluginName] = (options) ->
return @.each () ->
($.data @, 'plugin_' + _PluginName
new Plugin @, options
) unless $.data @, 'plugin_' + _PluginName
return
) jQuery, window, document
I'm not asking for a comparison between both plugins. And my plugin is not even close to perfect. I found out from answer to another question that using the ($, window, document)
closure is an overkill. There may be other faults and you are absolutely welcome to point them out and discuss them.
Nonetheless, I have some very specific questions.
Questions
How safe are these conventionally 'private' objects/methods. What if someone intentionally wanted to call
Plugin()
instead of using the plugin the right way? Could_Defaults
be accessed in any scope other than this closure?What exactly is the scope of these 'private' objects? Do they float around in jQuery namespace willy-nilly? Could they interfere with anything? How does using these 'private' variables help make the code better?
I don't completely understand
prototype
. Areinit()
anddestroy()
properties of thePlugin()
itself? Why doinit()
anddestroy()
refer to theoptions
property ofPlugin()
asthis.options
as ifinit()
anddestroy()
were defined inside the context ofPlugin()
itself... And what if I have an object defined asPlugin.prototype.methods
? What isthis
for the functions inside themethods
object?
NOTE: If it is difficult for anyone to follow links to view code, please let me know. I'll edit this question to include the code. I didn't include because then the question would become too long.