Reputation: 26281
I am trying to understand lines 10 and 12 of the below code, and have given my attempt to explain. Please correct me as applicable.
//Line 10
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
//Line 12
return methods.init.apply(this, arguments);
Line 10. If the argument provided to samplePlugin is a method, then make that method have the same this
as is at the current script's location (i.e. Line 10), and ... Help! Where is arguments
defined? What is with the call()
? EDIT. Okay, it seems Array.prototype.slice.call(arguments, 1)
makes a real array out of all the arguments except the first one, however, still is a bit of a mystery.
Line 12. Else if the argument provided to samplePlugin is an object or empty, then make the init
method have the same this
as is at the current script's location (i.e. Line 12), and ... Seems simpler, but still need help...
(function($){
var methods = {
init : function (options) {return this.each(function () {/* ... */});},
method1 : function () {return this.each(function () {/* ... */});},
method2 : function () {return this.each(function () {/* ... */});}
};
$.fn.samplePlugin = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); //Line 10
} else if (typeof method === 'object' || ! method) {
return methods.init.apply(this, arguments); //Line 12
} else {
$.error('Method ' + method + ' does not exist on jQuery.samplePlugin');
}
};
}(jQuery)
);
Upvotes: 2
Views: 249
Reputation: 82734
You unraveled some parts yourself, but there's a non-trivial part of JavaScript function trickery involved. Let's put them apart:
arguments
is a “magic” variable inside function bodies, that offers access to the function arguments. It's simply there without declaration, and works like an array but is no array (will become important in a moment).
If you want to access the first argument to a function, arguments[0]
is the place to look. In your specific function, that’s always identical to the variable method
.
If you want to get any additional arguments (remember, that you can call JS functions with any number of arguments, not just the ones declared), a first pass might look like this:
arguments.slice(1)
but, remember, arguments
is no array, it just looks like one. All Array
methods are missing. So we need to borrow them from Array.prototype
, where “real” arrays get them from:
Array.prototype.slice
To get slice
to work with arguments
, it must be called with arguments
as this
:
Array.prototype.slice.call(arguments, 1)
(Read up on Function.prototype.call
)
So far so good.
Now, imagine the jQuery plugin gets called like this:
$('body').samplePlugin('method1', 'foo', 'bar');
The variable method
is now "method1"
. The first if
is triggered, because there is a method1
key in methods
, and it's a function. So the function is called with all remaining arguments:
methods['method1'].apply(this, ['foo', 'bar']);
Second branch: If the plugin is called like this:
$('body').samplePlugin({ foo: 'bar' });
then method == { foo: 'bar' }
and we're landing in branch 2, since it's an object. The idea of the boilerplate author is, that in this case the init
method should be called:
methods['init'].apply(this, arguments);
(methods['init']
is the same as methods.init
in JS.) We do not need the splicing trick from above, since arguments[0]
is not any method name.
Upvotes: 4